如何从含嵌套联合类型的TypeScript接口中提取精确子类型?
解决嵌套联合类型的提取问题
这个问题我之前在项目里也碰到过,核心卡点在于**Extract只对顶层联合类型生效**——你的X是一个单一接口,里面的prop是嵌套的联合类型,所以直接用Extract去匹配时,根本找不到符合条件的顶层分支,自然返回never。
改成顶层联合(type X = { prop: Y } | { prop: Z })确实能解决,但手动改整个代码库显然不现实。我们可以写一个通用的类型工具,自动把所有嵌套的联合类型展开成顶层的笛卡尔积联合,这样就能继续用Extract来筛选了。
通用类型工具实现
下面是两个核心类型工具,能递归展开所有嵌套的联合类型:
// 拆分单个属性的联合,生成对应分支 type DistributeSingleProp<T, K extends keyof T> = T[K] extends infer U ? U extends any ? Omit<T, K> & { [P in K]: U } : never : never; // 递归遍历所有属性,展开所有嵌套联合 type ExpandAllNestedUnions<T> = T extends object ? keyof T extends infer K ? K extends keyof T ? ExpandAllNestedUnions<DistributeSingleProp<T, K>> : T : T : T;
使用示例
用你的类型定义来测试:
interface Y { readonly y: string; readonly type: 'y' } interface Z { readonly z: number; readonly type: 'z' } interface X { readonly prop: Y | Z } // 先展开嵌套联合:此时 ExpandedX 等价于 { readonly prop: Y } | { readonly prop: Z } type ExpandedX = ExpandAllNestedUnions<X>; // 再用 Extract 筛选,就能得到预期的类型 type ZfromX = Extract<ExpandedX, {readonly prop: { readonly type: 'z' }}>; // ZfromX 的结果是 { readonly prop: Z }
工具的通用性
这个工具不止能处理单个属性的嵌套联合,哪怕你的类型有多个带联合的属性,比如:
interface A { a: 'a1' | 'a2' } interface B { b: 'b1' | 'b2' } type C = { prop1: A; prop2: B }; type ExpandedC = ExpandAllNestedUnions<C>; // ExpandedC 会展开成四个分支的联合: // { prop1: { a: 'a1' }, prop2: { b: 'b1' } } | // { prop1: { a: 'a1' }, prop2: { b: 'b2' } } | // { prop1: { a: 'a2' }, prop2: { b: 'b1' } } | // { prop1: { a: 'a2' }, prop2: { b: 'b2' } }
这样不管你的类型结构多复杂,都能自动把所有嵌套的联合展开成顶层的笛卡尔积联合,之后用Extract、Exclude这些工具就都能正常工作了。
内容的提问来源于stack exchange,提问作者roomcayz
相关产品推荐
相关产品推荐

