我正在尝试创建一个函数,它将接受一个对象作为map,并且一个进一步嵌套的函数将使用它的键(我将来也需要这个值):
function exec(a: string) {
return a;
}
function one<T extends Record<string, any>>(a: T) {
return <K extends keyof T>(b: K) => {
exec(b);// TS2345: Argument of type 'string | number | symbol' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'.
};
}
但我得到这个错误TS2345: Argument of type 'string | number | symbol' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'.
,因为对象键可能是number|符号,而不是严格的字符串。可以不使用exec(b.toString())
吗?
1条答案
按热度按时间wribegjk1#
正如你所注意到的,字符串索引签名并不能阻止非
string
键的存在(这只意味着任何存在的string
键都需要具有与索引签名兼容的属性,这对于Record<string, any>
来说是非常宽松的)。即使U
没有特定的属性键,这并不意味着T
不能拥有该键。本质上,TypeScript中的对象类型是 open 而不是 exact(如microsoft/TypeScript#12936中所要求的),并且在大多数情况下,编译器不会禁止多余的属性。这意味着你可以像这样调用
one
:这就是为什么
one
的实现抱怨b
可能不是string
。如果你想防止这种情况,你需要将
K
约束为不仅仅是keyof T
,而是keyof T
的子类型,也可以分配给string
。最简单的表达方法是将string
与keyof T
相交:现在编译器知道
b
必须是keyof T
以及string
。现在如果你试图用非string
输入调用从one
返回的函数,你会得到想要的错误:Playground链接到代码