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

如何阻止TypeScript允许重新赋值联合类型的辨别符?

解决TypeScript联合类型判别属性可赋值导致的运行时错误

这段代码编译通过但运行时抛错的核心原因是:TypeScript允许修改联合类型的共享判别属性kind,但修改后类型推断和对象实际结构不匹配。你传入Bar类型的对象,把kind改成"foo"后,TypeScript认为这是Foo类型,允许访问foo属性,可原对象根本没有这个属性,自然报错。

下面是几种解决方法:

方案1:把判别属性设为readonly(推荐)

别觉得这是权宜之计——判别属性本来就是用来标记固定类型的,不应该被修改。给kind加上readonly能从根源上禁止赋值操作:

type Foo = {
    readonly kind: "foo",
    foo: { foo: string };
}

type Bar = {
    readonly kind: "bar",
    bar: { bar: string};
}

type Union = Foo | Bar;

function doSomething(fooOrBar: Union) {
    // fooOrBar.kind = "foo"; // 这里直接编译报错,无法修改只读属性
    if(fooOrBar.kind === "foo")
        console.log(fooOrBar.foo.foo);
}

方案2:用映射类型统一加readonly约束

如果不想逐个修改每个类型的kind,可以用映射类型给联合类型的kind统一加上只读限制:

type Foo = {
    kind: "foo",
    foo: { foo: string };
}

type Bar = {
    kind: "bar",
    bar: { bar: string};
}

type Union = Foo | Bar;
// 给联合类型的kind属性添加readonly约束
type ImmutableKindUnion = Union & { readonly kind: Union["kind"] };

function doSomething(fooOrBar: ImmutableKindUnion) {
    // fooOrBar.kind = "foo"; // 编译报错
    if(fooOrBar.kind === "foo")
        console.log(fooOrBar.foo.foo);
}

方案3:用不可变操作创建新对象

不修改原对象,而是生成一个符合目标类型的新对象,确保类型和实际结构完全匹配:

function doSomething(fooOrBar: Union) {
    // 生成完整的Foo类型新对象,按需补充属性
    const fooObj: Foo = {
        kind: "foo",
        foo: { foo: "default" },
        ...fooOrBar // 合并原对象的其他属性(如果有)
    };
    console.log(fooObj.foo.foo);
}

内容的提问来源于stack exchange,提问作者Dominik Berse

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:24:53