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

为何两个看似相同的TypeScript工具类型表现不同?

问题核心拆解与解答

1. 为什么基础泛型映射类型对联合类型失效?

你写的type IntersectProps<U> = { [K in keyof U]: U[K]; },当传入联合类型A|B时触发了TypeScript的分布映射类型特性:当映射类型的泛型参数是联合类型时,TS会自动将联合类型的每个成员单独代入映射逻辑,再把结果重新联合起来。

具体来说,IntersectProps<A|B>会被展开为:

IntersectProps<A> | IntersectProps<B>

而IntersectProps<A>等价于A本身,IntersectProps<B>等价于B本身,所以最终结果还是A|B,而非预期的交集类型。

但你直接写{ [K in keyof (A | B)]: (A | B)[K]; }时,keyof (A|B)是一个具体的联合字面量'x'|'y',没有泛型参数的分布逻辑,因此能正确生成交集类型。

2. 为什么添加默认泛型参数后生效?

修改后的类型:

type IntersectProps<U, T extends keyof U = keyof U> = { [K in T]: U[K]; }

关键在于默认参数的计算时机:T的默认值keyof U是在泛型实例化时一次性计算的,而非映射阶段的分布计算。当U是A|B,keyof U直接得到'x'|'y',T被固定为这个值,后续的映射基于固定的T遍历,不会触发分布逻辑,因此生成的是包含x和y的单一对象类型,也就是你需要的交集类型。

你也可以显式传入T验证:

type Test = IntersectProps<A|B, keyof (A|B)>; // 同样得到{x?: string; y?: string;}

3. 为什么A|B看起来像包含所有可选属性的类型?

TypeScript对联合类型的对象会做简化显示。实际上A|B是两个对象类型的联合,但TS在显示时会把两个类型的所有属性都列出来并标记为可选——因为联合类型的实例可以是A(含x、y、z)、B(含x、y、w),甚至只含x、y的对象。这种显示方式是为了直观展示所有可能存在的属性,但本质上它仍然是A和B的联合类型,而非单一对象类型。

可以通过类型收窄验证:

declare const val: A|B;
if ('z' in val) {
  val; // 类型收窄为A
} else if ('w' in val) {
  val; // 类型收窄为B
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:23:13