TypeScript为何不支持以类型作为区分符?代码报错咨询
为什么这段TypeScript代码无法编译?类型联合为什么不能直接作为区分符?
问题分析
你写的代码里,AorB 是 A | B 的联合类型,TypeScript 对联合类型的匹配规则是:返回值必须完全符合联合类型中的某一个具体类型,而不是把每个属性的类型简单合并成联合类型。
现在你返回的对象结构是 {foo: number; bar: string; inner: A1 | B1},这个类型既不符合 A(因为 inner 可能是 B1,而 A 要求 inner 必须是 A1),也不符合 B(同理,inner 可能是 A1,不符合 B 对 inner 是 B1 的要求),所以编译器会报错。
至于为什么不能用类型当区分符——因为你定义的 A 和 B 属于非可辨识联合:它们没有一个共同的、类型为字面量的属性(比如 type: 'A'/type: 'B')来让 TypeScript 明确区分当前对象到底是 A 还是 B。编译器无法跟踪 inner 的类型和外层对象的关联关系,它只能看到 inner 是 A1 | B1,因此判定整个返回对象不符合 AorB 的要求。
解决方法
方法1:使用类型断言明确分支类型
直接告诉编译器每个分支返回的是 A 还是 B:
export interface A1 { plop: number; } export interface B1 { hop: number; } export interface A { foo: number; bar: string; inner: A1; } export interface B { foo: number; bar: string; inner: B1; } export type AorB = A | B; function test(): AorB { if (Math.random() > 0.5) { return { foo: 42, bar: 'plop', inner: {plop: 4} } as A; } else { return { foo: 42, bar: 'plop', inner: {hop: 43} } as B; } }
方法2:改成可辨识联合类型
给 A 和 B 新增一个共同的字面量属性作为区分符,让编译器能自动推导类型:
export interface A1 { plop: number; } export interface B1 { hop: number; } export interface A { type: 'A'; // 新增区分属性 foo: number; bar: string; inner: A1; } export interface B { type: 'B'; // 新增区分属性 foo: number; bar: string; inner: B1; } export type AorB = A | B; function test(): AorB { if (Math.random() > 0.5) { return { type: 'A', foo: 42, bar: 'plop', inner: {plop: 4} }; } else { return { type: 'B', foo: 42, bar: 'plop', inner: {hop: 43} }; } }
方法3:提前声明分支对象并指定类型
通过提前创建指定类型的对象,让编译器自动确认返回值符合要求:
export interface A1 { plop: number; } export interface B1 { hop: number; } export interface A { foo: number; bar: string; inner: A1; } export interface B { foo: number; bar: string; inner: B1; } export type AorB = A | B; function test(): AorB { if (Math.random() > 0.5) { const result: A = { foo: 42, bar: 'plop', inner: {plop: 4} }; return result; } else { const result: B = { foo: 42, bar: 'plop', inner: {hop: 43} }; return result; } }
内容的提问来源于stack exchange,提问作者boehm_s
相关产品推荐
相关产品推荐

