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

TypeScript联合类型父子接口场景及函数返回类型的疑问

TypeScript父子接口联合类型的常见疑问解析

先纠正一个核心误区:你之前对接口「宽泛程度」的判断搞反了。

先看你给出的基础类型例子:

type Test1 = never | any; // 结果是any,因为any包含never
type Test2 = "123" | string; // 结果是string,因为string包含所有字符串字面量

这里的逻辑是范围大的类型包含范围小的类型,联合后会被范围大的类型「吸收」。但接口的继承关系正好相反:

interface A1 { name: string }
interface A2 extends A1 { age: number }

A1的范围比A2大——所有拥有name属性的对象都符合A1,而A2要求必须同时有name和age,所以A2是A1的子类型(范围更小),而非更宽泛的类型。这就是为什么Test3 = A2 | A1不会收缩成A2:因为A1的实例(比如{name: "??"})并不满足A2的要求,TypeScript不可能把它们合并成A2,否则会出现类型不安全的情况,这和你自己的理解一致。

再看Test4 = A1 | Partial<A2>,Partial<A2>是{name?: string; age?: number},它和A1的联合依然是范围更大的集合:既包含只有name的A1实例,也包含各种可选属性的Partial实例,当然不等于要求name和age都必填的A2。


为什么keyof Test3的结果只有"name"?

TypeScript中,keyof (T | U)的规则是取所有联合成员的公共键。因为联合类型的变量可能是T的实例,也可能是U的实例,只有所有成员都存在的属性,才能保证在任何情况下都能安全访问。

对于Test3 = A1 | A2:

  • A1的键是"name"
  • A2的键是"name" | "age"
    两者的公共键只有"name",所以keyof Test3的结果就是"name"。

函数返回Test3时无法访问age的问题

当函数返回Test3类型时,TypeScript只知道返回值要么是A1,要么是A2,但不确定具体是哪一个。如果直接访问da.age,万一返回的是A1实例(比如record2),就会出现不存在的属性,这显然不安全。

要解决这个问题,需要做类型收窄,比如用类型守卫判断age是否存在:

const da = fn();
da.name; // 安全,因为A1和A2都有name

if ('age' in da) {
  da.age; // 这里TypeScript会把da的类型收窄为A2,可以安全访问age
}

或者如果你确定返回的一定是A2,也可以用类型断言:

(da as A2).age;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 11:05:20