TypeScript如何扩展/裁剪交叉类型内嵌套的联合类型成员?
实现方案
两种类型操作都可以在不重写原有类型定义的前提下完成,核心依赖TypeScript的两个核心特性:交叉类型对联合类型的分配律、内置条件类型的分配式行为。
扩展嵌套联合的成员
TypeScript中交叉类型作用于联合类型时会自动满足分配律,即(A | B) & C 与 (A & C) | (B & C) 是完全等价的结构类型。
基于这个规则,你不需要手动拆解原类型的结构,直接将原类型与「新增联合成员+原类型公共交叉部分」组成的类型做联合,就能得到目标扩展类型:
// 直接实现 type ExtendedUnionInsideIntersectionType = | UnionInsideIntersectionType // Omit自动提取原类型除foo外的所有公共字段,无需手动重复写baz等公共属性 | { foo: "qux" } & Omit<UnionInsideIntersectionType, "foo">;
TS会自动对类型做分配合并,最终推导的类型和你手写的({ foo: "foo" } | { foo: "bar" } | { foo: "qux" }) & { baz: "baz" }完全等价。不需要纠结TS hover提示时的类型展示形式,TypeScript是结构类型系统,只要类型的成员结构一致,不管书写形式是交叉嵌套联合还是展开后的联合,类型检查、属性访问、赋值的行为没有任何差异。
如果需要复用逻辑,可以封装通用工具类型:
// 通用工具:给带foo判别字段的交叉联合类型新增foo成员 type ExtendFooUnion<T, NewFooValue extends string> = | T | { foo: NewFooValue } & Omit<T, "foo">; // 使用 type Extended = ExtendFooUnion<UnionInsideIntersectionType, "qux">;
移除嵌套联合的指定成员
你提到的内置Exclude工具类型完全适用于这个场景。因为交叉联合经过分配律展开后本身就是普通联合类型,Exclude会自动遍历联合的每一个成员,筛掉符合匹配条件的分支:
// 直接实现 type RestoredUnionInsideIntersectionType = Exclude<ExtendedUnionInsideIntersectionType, { foo: "qux" }>;
上述代码会把所有foo值为"qux"的联合成员全部排除,剩下的类型结构和原始的UnionInsideIntersectionType完全一致,可以互相赋值。
同样可以封装通用工具类型:
// 通用工具:从带foo判别字段的交叉联合类型移除指定foo成员 type RemoveFooUnion<T, RemoveFooValue extends string> = Exclude<T, { foo: RemoveFooValue }>; // 使用 type Restored = RemoveFooUnion<ExtendedUnionInsideIntersectionType, "qux">;
注意:该方案对判别式联合(即通过
foo这类单字段区分不同联合成员的类型)100%生效;如果是无明确判别字段的联合类型,需要调整Exclude的匹配条件,避免误删结构匹配的其他成员。
内容的提问来源于stack exchange,提问作者thisisrandy
相关产品推荐
相关产品推荐

