Ограничения на элементы интерфейса в обобщениях машинописи - PullRequest
0 голосов
/ 10 октября 2018

У меня есть метод, который должен принимать любой объект, при условии, что все его поля являются строками или числами

Я сделал это, что прекрасно работает при наборе утки

static interpolateParams(
    route: string, 
    params: {[key: string] : string | number}) : string {

    const parts = route
        .split("/")
        .map(part => {
            const match = part.match(/:([a-zA-Z09]*)\??/);
            if (match) {
                if (!params[match[1]]) {
                    console.error("route argument was not provided", route, match[1]);
                    return part;
                }

                return params[match[1]];
            }
            else {
                return part;
            }
        })

    return "/" + parts.slice(1).join("/");
}

иcall

interpolateParams("/api/:method/:value", {method: "abc", value: 10});

Теперь я хочу заставить interpolateParams принять любой интерфейс для маршрута params.

interpolateParams<IABCParams>("/api/:method/:value", {method: "abc", value: 10});

Проблема заключается в том, что он по-прежнему должен соответствовать ограничениям для всехполя, являющиеся строками или числами

Есть ли способ указать общее ограничение для всех полей данного интерфейса определенного типа?

Я пытался это сделать

static interpolateParams<T extends {[key: string] : string | number}>(
    route: string, 
    params: T) : string {

и, очевидно, получил это

Тип 'IABCParams' не удовлетворяет ограничению '{[key: string]: string |число;} '.

Отсутствует подпись индекса в типе' IABCParams '.

Спасибо

Ответы [ 3 ]

0 голосов
/ 10 октября 2018
Ограничение

T может относиться к T (с некоторыми ограничениями), поэтому вы можете использовать сопоставленный тип для генерации ограничения, которое имеет те же поля, что и T:

function interpolateParams<T extends {[P in keyof T] : string | number}>(
    route: string, 
    params: T) : string { /*...*/ }

Остерегайтесь того, что обман с ограничениями параметров циклического типа может иногда вызывать проблемы, хотя этот сценарий, вероятно, будет в порядке.

0 голосов
/ 11 октября 2018

Вот окончательная версия, спасибо Мэтту за подсказку

static interpolateParams(
    route: string, 
    params: {[key: string] : string | number}) : string {

    const parts = route
        .split("/")
        .map(part => {
            const match = part.match(/:([a-zA-Z09]*)\??/);
            if (match) {
                if (!params[match[1]]) {
                    if (part.endsWith("?")) {
                        return null;
                    }

                    console.error("route argument was not provided", route, match[1]);
                    return part;
                }

                return params[match[1]];
            }
            else {
                return part;
            }
        }).filter(p => p && p != "");

    return "/" + parts.join("/");
}

static formatRoute<T extends {[P in keyof T] : string | number}>(
    route: string,
    params: T
) : string {
    return interpolateParams(route, params);
}
0 голосов
/ 10 октября 2018

Если вы хотите, чтобы interpolateParams("/api/:method/:value", {method: "abc", value: 10}); проверил, вы не можете.Это потому, что вы ничего не можете сделать из "/api/:method/:value", чтобы дать вам method,value подпись.

Обходной путь

Напишите функции, которые принимают method и value и используют его для питания и конфигурации и использования.

Например, эту стратегию я использую с takeme .

// Define 
export const links = {
  profile: (id: string) => `/profile/${id}`
}

// Use in Configure 
links.profile(':profileId')

// Use in Navigate / a tags
links.profile(user.id)
...