You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 22:54:03