Typescript泛型对接口成员的约束

时间:2018-10-09 22:34:59

标签: typescript generics interface constraints

我有一个方法,只要它的所有字段都是字符串或数字,它就可以接受任何对象

我做了这个,非常适合鸭子打字

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("/");
}

并致电

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'不满足约束'{[键:字符串]:字符串|数; }'。

     

“ IABCParams”类型中缺少索引签名。

谢谢

3 个答案:

答案 0 :(得分:3)

D:\avsts140\_work\2\.tmp\node_modules\.bin;的约束可以引用T(有一些限制),因此您可以使用映射类型生成与T具有相同字段的约束:

T

请注意,使用循环类型参数约束的欺骗有时可能会导致问题,尽管这种情况很可能会解决。

答案 1 :(得分:1)

这是最终版本,感谢马特的提示

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);
}

答案 2 :(得分:0)

如果您想interpolateParams("/api/:method/:value", {method: "abc", value: 10});进行类型检查,则不能。这是因为您无法推断出有关"/api/:method/:value"的任何信息以给您method,value签名。

解决方法

编写带有methodvalue的函数,并使用它们为配置和使用提供动力。

例如这是我与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)