【发布时间】:2019-05-30 03:35:09
【问题描述】:
我正在从 TypeScript 模块导入以下类型和函数:
type Attributes = {
[key: string]: number;
};
function Fn<KeysOfAttributes extends string>(opts: { attributes: Attributes }): any {
// ...
}
我无法修改上面的代码。
然后我在自己的模块中实现以下代码:
// variant 1
const attributes = { // this object is hard coded (not dynamically generated)
foo: 1,
bar: 2,
baz: 3
};
type Type = typeof attributes;
type Keys = keyof Type;
Fn<Keys>({
attributes
});
一切都很完美。现在我想将类型Attributes 类型分配给常量attribute,因为我想确保键是字符串,值是数字。所以我修改了我的代码:
// variant 2
const attributes: Attributes = {
foo: 1,
bar: 2,
baz: 3
};
type Type = typeof attributes;// equals {[key: string]: number;}
type Keys = keyof Type;// equals string | number. Why ?
Fn<Keys>({// Here, I would like Keys to be "foo" | "bar" | "baz", instead I have string | number
attributes
});
我在Fn<Keys>({ 行收到以下错误:
Type 'string | number' does not satisfy the constraint 'string'.
Type 'number' is not assignable to type 'string'.ts(2344)
我不明白为什么类型Keys等于string | number,当索引签名明确指定key是一个字符串?
如何确保 "foo" | "bar" | "baz" 类型作为类型参数而不是 string | number 被传递?
我可以接受第一个变体,但我不明白为什么第二个不起作用。 有什么想法吗?
非常感谢
【问题讨论】:
-
您将类型扩展为字符串索引类型,编译器尽职尽责地期望它可以有任何键。也就是说,没有什么可以阻止程序中的某些代码执行
attributes.potato = 123。所以keyof typeof attributes是string(好吧,| number是为了方便)。如果您想要两全其美,请创建一个像const asAttributes = <A extends Attributes>(a:A) => a这样的辅助函数,然后将其称为const attributes = asAttributes({foo: 1, bar: 2, baz:3});
标签: typescript