打字稿模板文字作为界面键

假设我想在打字稿中创建一个包含多个项目的对象,如下所示:

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 = <K extends PropertyKey>(
    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 链接到代码


以上是打字稿模板文字作为界面键的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>