Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
typescript泛型中接口成员的约束_Typescript_Generics_Interface_Constraints - Fatal编程技术网

typescript泛型中接口成员的约束

typescript泛型中接口成员的约束,typescript,generics,interface,constraints,Typescript,Generics,Interface,Constraints,我有一个方法,它应该接受任何对象,只要它的所有字段都是字符串或数字 我做了这个,用duck打字效果很好 static interpolateParams( route: string, params: {[key: string] : string | number}) : string { const parts = route .split("/") .map(part => { const match

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

我做了这个,用duck打字效果很好

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<IABCParams>("/api/:method/:value", {method: "abc", value: 10});
插值图(“/api/:method/:value”,{method:“abc”,value:10});
问题是,它仍然应该匹配字符串或数字的所有字段的约束

有没有办法将给定接口的所有字段上的泛型约束指定为特定类型

我试过了

static interpolateParams<T extends {[key: string] : string | number}>(
    route: string, 
    params: T) : string {
静态插值图(
路线:字符串,
参数:T):字符串{
很明显,我得到了这个

类型“IABCParams”不满足约束“{[key:string]:string | number;}”

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


感谢如果你想要
插值图(“/api/:method/:value”,{method:“abc”,value:10});
来进行类型检查,你不能。这是因为你不能推断出任何关于
“/api/:method/:value”
的信息来给你一个
方法,值
签名

变通办法 编写采用
方法
的函数,并使用它为配置和使用提供动力

这就是我使用的策略


T
的约束可以引用
T
(有一些限制),因此您可以使用映射类型生成与
T
具有相同字段的约束:

function interpolateParams<T extends {[P in keyof T] : string | number}>(
    route: string, 
    params: T) : string { /*...*/ }
函数插值图(
路线:字符串,
参数:T):字符串{/*…*/}

请注意,使用循环类型参数约束的技巧有时可能会导致问题,尽管这种情况可能不会有问题。

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

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);
}
静态插值图(
路线:字符串,
参数:{[key:string]:string | number}):string{
常数部分=路线
.拆分(“/”)
.map(部分=>{
常数匹配=零件匹配(/:([a-zA-Z09]*)\??/);
如果(匹配){
如果(!params[匹配[1]]){
if(带(“?”)的部分末尾){
返回null;
}
错误(“未提供路由参数”,路由,匹配[1]);
返回部分;
}
返回参数[匹配[1]];
}
否则{
返回部分;
}
}).filter(p=>p&&p!=“”);
返回“/”+零件。连接(“/”);
}
静态格式化路由(
路线:字符串,
参数:T
):字符串{
返回插值图(路线、参数);
}

我的猜测是:不,没有。我希望是错误的。@AndrewShepherd如果sems是可能的,请检查Matt的评论和我的最终版本thanksOk,该版本运行得不太好,但使用附加层似乎欺骗了解释器:)如您所述,
中的错误如果(!params[match[1]])
line-没有索引器。所以我按照您的建议添加了另一个版本的interpolateRoute,并在内部调用bare interpolate(代码见下一步)
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);
}