这是打字稿中的预期行为吗?
const NeedsRecord = <T extends Record<string, any>>(record: T) => {}
NeedsRecord({
5: "? Should error, doesn't ?"
});
我想通过继承约束Record
的键类型。我该怎么办?
将键类型作为通用参数也无法按预期工作:
const NeedsRecord = <T extends string>(record: Record<T, any>) => { }
NeedsRecord({
5: "? Should error, doesn't ?"
});
明确定义联合键类型有效,但使用起来很丑:
const NeedsRecord = <T extends string>(record: Record<T, any>) => { }
NeedsRecord<"a"|"b">({
a: "works",
b: "works",
// 5: "? fails properly"
// c: "? fails properly"
});
答案 0 :(得分:2)
这是预期的TypeScript行为。 “数字”对象键为actually strings,因此TypeScript将字符串索引签名视为supporting number and even symbol keys。
如果要在传递number
值的键时强制编译器产生错误,则可以这样做:
const needsRecord = <T extends { [K in keyof T]: K extends number ? never : any }>(
record: T
) => { }
needsRecord({
a: "works",
b: "works",
5: "error" // string is not assignable to never
});
但是要注意...在JavaScript中,{5: ""}
和{"5": ""}
之间确实没有区别,因为键被强制转换为字符串:
const oN = { 5: "" };
console.log(typeof (Object.keys(oN)[0])); // "string"
const oS = { "5": "" };
console.log(JSON.stringify(oS) === JSON.stringify(oN)); // true
这意味着上面的needsRecord()
会认为这很好:
needsRecord({
a: "works",
b: "works",
"5": "oops" // no error
})
但是没有充分的理由允许一个不允许另一个。而且TypeScript目前还没有一种很好的内置方式来排除“类似数字的字符串”,因此我不确定在这里可以做更多的事情。
鉴于5
和"5"
作为密钥是相同的,为什么您实际上关心禁止这样做? TypeScript的预期行为实际上对于您的用例是否可以接受?还是如果允许数字键,实际上会出问题吗?