Typescript如何定义字段引用自身的递归可辨识联合类型
TypeScript可辨识联合自引用的最优实现方案
核心实现
TypeScript原生支持类型的前向引用,你遇到的「先使用后声明报错」是linter配置问题而非TypeScript本身的语法限制,最优方案就是直接在接口字段中引用后续声明的联合类型即可,不需要额外的类型体操或者强制类型转换。
修正后的完整代码如下:
interface Base { kind: string; someOtherCommonField?: any; } interface A extends Base { kind: "A"; children: TheNode[]; // 直接引用后续声明的联合类型即可 } interface B extends Base { kind: "B"; fieldB: number; } type TheNode = A | B; function makeNode(): TheNode { return {kind: "A", children: []}; } const a = makeNode(); if (a.kind === "A") { for (let c of a.children) { if (c.kind === "A") { // 不需要手动强转,TS可通过可辨识联合的特征直接推断c为A类型 console.log(c.children); } } }
原理说明
- TypeScript的类型声明不存在变量的临时死区限制,只要联合类型
TheNode在同一个作用域内完成最终声明,就可以在之前的接口定义中直接引用。 - 如果你使用ESLint校验,需要调整规则避免误报:关闭原生的
no-use-before-define规则,启用@typescript-eslint/no-use-before-define规则并配置忽略类型引用的检查即可。
兜底兼容方案
如果暂时无法调整linter配置,可以用接口合并的方式做前向占位,实现同样的类型效果:
interface Base { kind: string; someOtherCommonField?: any; } // 预先声明占位接口 interface TheNodePlaceholder {} interface A extends Base { kind: "A"; children: TheNodePlaceholder[]; } interface B extends Base { kind: "B"; fieldB: number; } type TheNode = A | B; // 合并占位接口和实际联合类型 interface TheNodePlaceholder extends TheNode {}
内容的提问来源于stack exchange,提问作者sky
相关产品推荐
相关产品推荐

