TypeScript中如何从联合类型中正确移除空接口类型
问题原因
TypeScript 采用结构类型系统进行兼容性判断,空对象类型 {} 可以兼容所有非 null/undefined 的对象类型,因此直接使用 Exclude<Union, A> 时,联合类型里的 B、C、D 都满足 extends {} 的判断条件,会被全部排除,最终得到 never 类型,不符合预期。
解决方案
我们可以自定义工具类型,通过判断类型是否没有自有属性来严格识别空对象,再从联合类型中过滤掉这类空对象:
// 工具类型:判断T是否为严格的空对象类型 type IsStrictEmptyObject<T> = [keyof T] extends [never] ? true : false; // 工具类型:从联合类型U中移除空对象类型 type RemoveEmptyObject<U> = U extends unknown ? IsStrictEmptyObject<U> extends true ? never : U : never; // 实际使用 type UnionWithoutA = RemoveEmptyObject<Union>; // 最终得到的UnionWithoutA类型为:B | C | D
实现原理
keyof T会返回类型T所有自有属性名的联合类型,空对象类型的keyof结果为never,而B/C/D都有明确的属性,keyof结果都是非never的字符串字面量联合。- 条件类型中使用
U extends unknown是为了触发联合类型的分布式条件判断,会遍历联合类型的每一个成员单独执行判断逻辑,符合条件的成员返回never(即从联合中移除),不符合的成员保留,最终合并得到过滤后的联合类型。
内容的提问来源于stack exchange,提问作者Albert Gao
相关产品推荐
相关产品推荐

