如何阻止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
相关产品推荐
相关产品推荐

