作者:大胡子姐姐爱油面巾塞肉 | 来源:互联网 | 2023-09-14 13:29
假设我想在打字稿中创建一个包含多个项目的对象,如下所示:
const obj: Items = {
item1: 'foo',
item2: 'bar',
item3: 'baz',
}
我应该如何声明我的 Items 类型以使其与任意数量的项目兼容?我使用 Typescript 4.1 中的模板文字尝试了以下操作,但它似乎不起作用:
interface Items {
[P: `array${number}`]: any;
}
是否可以声明这样的类型?
回答
TS4.4+ 更新
TypeScript 4.4 将支持包含模式模板文字的索引签名,如在microsoft/TypeScript#44512 中实现的那样。然后,您将能够声明Items
为特定类型,如下所示:
interface Items {
[key: `item${number}`]: any;
}
您可以验证它是否按需要工作:
const obj: Items = {
item1: 'foo',
item2: 'bar',
item2021: 'baz',
item3: 'qux',
};
const objBad: Items = {
item1: 'foo',
item2: 'bar',
itemMMXXI: 'baz', // error!
// ~~~~~~~~~ <--
// Object literal may only specify known properties,
// and 'itemMMXXI' does not exist in type 'Items'
item3: 'qux'
};
Playground 链接到代码
TS4.1-4.3 的答案
从 TypeScript 4.1 开始,当前不允许将表单的模式模板文字`item${number}`
(如在microsoft/TypeScript#40598 中实现)作为键类型。
目前没有与您想要的Items
类型相对应的特定类型。相反,您可以将其表示为对类型的约束并编写一个asItems()
仅接受遵守约束的输入的辅助函数:
const asItems = (
obj: { [P in K]: P extends `item${number}` ? any : never }
) => obj;
obj
将检查传入的每个键是否可分配给`item${number}`
。如果是,则属性类型为any
,否则,属性类型为never
。这往往会导致任何违规属性出现错误:
const obj = asItems({
item1: 'foo',
item2: 'bar',
item2021: 'baz',
item3: 'qux',
}); // okay
const objBad = asItems({
item1: 'foo',
item2: 'bar',
itemMMXXI: 'baz', // error!
// ~~~~~~~~~ <-- Type 'string' is not assignable to type 'never'
item3: 'qux'
});
Playground 链接到代码