我有一些TypeScript接口,有许多重复的,类似的字段.例如:

interface Foo {
   person1Name: string;
   person1Address: string;
   person2Name: string;
   person2Address: string;
   category: string;
   department: string;
}

我试着通过使用Typescribe索引签名模板来缩短它,它使用了[key: 'person${number}Name']这样的东西.然而,我想限制允许键的数量,说5个'person'属性,它没有工作的预期.

type AllowedIndex = 1 | 2 | 3 | 4 | 5;

interface Foo {
   [key: `person${AllowedIndex}Name`]: string;
   [key: `person${AllowedIndex}Address`]: string;
   category: string;
   department: string;
}

上面给出的错误是An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.ts(1337).

有没有办法做到我正在做的事?还是我一直在重复按键?

这是我试过的TS Playground Link分.

推荐答案

TypeScript 4.4 introducedindex signatures中使用patternplaceholder的能力template literal types(如microsoft/TypeScript#40598中实现的).但`person${AllowedIndex}Name`不是模式模板文字类型.事实上,它甚至不是一个模板文字类型,因为它被TypeScriptEager 地判断为字符串literal types"person1Name" | "person2Name" | "person3Name" | "person4Name" | "person5Name"union. 而且不能在索引签名中使用字符串文字类型的联合.

相反,您可以使用mapped types来创建一个对象类型,其键是字符串字面量的联合. 如果您希望这些密钥是必需的,则看起来像{[K in `person${AllowedIndex}Name`]: string},如果您希望它们是可选的,则看起来像{[K in `person${AllowedIndex}Name`]?: string}.同样,你可以使用PartialRecord实用程序类型的组合,如Partial<Record<`person${AllowedIndex}Name`, string>>.

请注意,映射类型是它们自己的类型,不能向它们添加属性.如果你想组合几个映射类型,你可以使用intersection. 或者,如果你想以interface结束,你可以使用interface extension来组合父映射类型(但只能通过一个命名类型,如PartialRecord)和你添加的属性.这给

type AllowedIndex = 1 | 2 | 3 | 4 | 5;

interface Foo extends
   Partial<Record<`person${AllowedIndex}Name`, string>>,
   Partial<Record<`person${AllowedIndex}Address`, string>> {
   category: string;
   department: string;
}

你可以判断它以确保它的行为符合要求:

type ExpandedFoo = {[K in keyof Foo]: Foo[K]};
/* type ExpandedFoo = {
    category: string;
    department: string;
    person1Name?: string | undefined;
    person2Name?: string | undefined;
    person3Name?: string | undefined;
    person4Name?: string | undefined;
    person5Name?: string | undefined;
    person1Address?: string | undefined;
    person2Address?: string | undefined;
    person3Address?: string | undefined;
    person4Address?: string | undefined;
    person5Address?: string | undefined;
} */

Playground link to code

Javascript相关问答推荐

不渲染具有HTML参数的React元素

Klaro与Angular的集成

如何在RTK上设置轮询,每24小时

Google Apps脚本中的discord邀请API响应的日期解析问题

如何在Obsidian dataview中创建进度条

Chromium会将URL与JS一起传递到V8吗?

无法使用单击按钮时的useState将数据从一个页面传递到另一个页面

用JS从平面文件构建树形 struct 的JSON

同一类的所有div';S的模式窗口

如何在Press上重新启动EXPO-AV视频?

expo 联系人:如果联系人的状态被拒绝,则请求访问联系人的权限

如何在Java脚本中对数据进行签名,并在PHP中验证签名?

无法设置RazorPay订阅API项目价格

如何在脚本编译后直接将RxJ模块导入浏览器(无需Angel、webpack、LiteServer)

重新呈现-react -筛选数据过多

在传单的图像覆盖中重新着色特定 colored颜色 的所有像素

使用Java脚本替换字符串中的小文本格式hashtag

如何将值从后端传递到前端

如果未定义,如何添加全局变量

检测带有委托的元素内部的点击,以及元素何时按其类名被选中