TypeScript中能否将推断类型作为计算接口的属性名?
问题:动态添加推断出的属性到TypeScript条件类型中
原始代码与预期行为
以下代码可正常运行,会生成两个不同类型的变量:
export class UnderTest<N extends string> { name: N; } export type Tester<T> = T extends UnderTest<infer N> ? { name: `${N}`, passed: true } : { passed: false }; let x: Tester<Object>; // 类型为 { passed: false } let y: Tester<UnderTest<"foo">>; // 类型为 { name: "foo", passed: true }
需求与错误
想要修改Tester<T>的匹配成功分支,添加一个以推断出的N命名的属性,理想写法如下:
export type Tester<T> = T extends UnderTest<infer N> ? { name: `${N}`, passed: true, `${N}`: "Yes, baby!" } : { passed: false };
期望y: Tester<UnderTest<"foo">>能拥有foo: "Yes, baby!"属性,但在TypeScript 4.8.4版本中会触发以下错误:
esri/views/shadergraph/v6.ts:59:41 - error TS1131: Property or signature expected. 59 ? { name: `${N}`, passed: true, `${N}`: "Yes, baby!" } ~~~ esri/views/shadergraph/v6.ts:59:47 - error TS1005: ';' expected. 59 ? { name: `${N}`, passed: true, `${N}`: "Yes, baby!" } ~ esri/views/shadergraph/v6.ts:59:62 - error TS1128: Declaration or statement expected. 59 ? { name: `${N}`, passed: true, `${N}`: "Yes, baby!" } ~ esri/views/shadergraph/v6.ts:60:9 - error TS1128: Declaration or statement expected. 60 : { passed: false }; ~
可行实现方案
在TypeScript中,要创建带动态键的对象类型,需结合映射类型与交叉类型来实现,修正后的代码如下:
export class UnderTest<N extends string> { name: N; } export type Tester<T> = T extends UnderTest<infer N> ? { name: `${N}`, passed: true } & { [K in N]: "Yes, baby!" } : { passed: false }; let y: Tester<UnderTest<"foo">>; // y的类型为:{ name: "foo"; passed: true; } & { foo: "Yes, baby!" } // 等价于:{ name: "foo"; passed: true; foo: "Yes, baby!" }
原理说明
- 直接在对象字面量中使用
${N}作为键的写法存在语法解析问题,而映射类型{ [K in N]: "Yes, baby!" }可以正确生成以推断出的N为键的类型。 - 通过交叉类型
&将固定属性的对象({ name:${N}, passed: true })与动态键的映射类型合并,即可得到包含目标属性的最终类型。
内容的提问来源于stack exchange,提问作者damix911
相关产品推荐
相关产品推荐

