如何优化TypeScript中将T | undefined类型键转为可选键的实现?
如何优化将含undefined的联合类型键转为可选键的TypeScript类型工具?
问题背景
你想要实现一个类型转换器,接收任意继承Record<string, any>的类型,把其中类型为T | undefined的键转为可选键,其余键保持必填。你的示例需求很清晰:
// 输入类型 type WithUndefined = { a: string, b: number | undefined, c: boolean | undefined, }; // 期望输出类型 type WithoutUndefined = { a: string, b?: number, c?: boolean, }
但你当前的实现拆分了多个辅助类型(OnlyKeepsDefined、OnlyKeepsUndefined、RemoveUnionUndefined),不仅代码冗余,还导致VSCode无法在悬浮提示中解析最终类型,完全违背了提升可读性的初衷。
优化后的简洁实现
我们可以利用TypeScript的映射类型条件判断和交叉类型合并,用更紧凑的代码实现需求,同时保证编辑器能正确解析最终类型:
type UndefinedToOptional<T extends Record<string, any>> = // 处理必填键:保留不含undefined的键和原类型 { [K in keyof T as undefined extends T[K] ? never : K]: T[K] } & // 处理可选键:提取含undefined的键,转为可选并移除undefined类型 { [K in keyof T as undefined extends T[K] ? K : never]?: Exclude<T[K], undefined> } // 交叉后重新映射为一个干净的对象类型,让编辑器能正确显示 extends infer O ? { [K in keyof O]: O[K] } : never;
代码解释
- 必填键处理:第一个映射类型通过条件判断,只保留那些类型中不包含
undefined的键,保持它们的必填状态和原类型。 - 可选键处理:第二个映射类型提取类型中包含
undefined的键,将它们标记为可选(?),同时用Exclude<T[K], undefined>移除类型中的undefined。 - 合并为干净类型:通过
infer和重新映射,把交叉后的类型合并成一个单一的对象类型,这样VSCode的悬浮提示就能正确显示最终的结构,而不是显示交叉类型的原始形式。
测试验证
用你提供的测试类型验证:
type TestType = { a: string; b: number | undefined; c: undefined; }; type FilteredTestType = UndefinedToOptional<TestType>; // 编辑器悬浮提示会显示清晰的最终类型: // { // a: string; // b?: number; // c?: never; // }
对应的合法赋值依然全部有效:
const a: FilteredTestType = { a: "a" }; const b: FilteredTestType = { a: "a", b: 1 }; const c: FilteredTestType = { a: "a", b: 1, c: undefined };
对比优势
和你原来的实现相比,这个优化版本:
- 代码更紧凑,不需要拆分多个辅助类型,可读性更强
- 编辑器能正确解析并显示最终的类型结构,符合你提升可读性的初衷
- 逻辑更直观,直接拆分必填和可选两部分处理,容易理解
内容的提问来源于stack exchange,提问作者Quadear
相关产品推荐
相关产品推荐

