如何编写TypeScript类型:移除对象中的null/undefined键值对
TypeScript 对象净化:移除含 null/undefined 键值对的类型实现
问题描述
需要编写一个TypeScript类型,将包含null或undefined值的对象T转换为移除这些键值对后的对象。现有尝试代码如下:
export const purifyObject = < T extends Record<string, unknown>, K extends keyof T, V extends K = T[K] extends null | undefined ? never : K, P = { [VK in keyof V]: T[VK] }, >( object: T, ): P => { const keys = Object.keys(object) as (keyof T)[]; return keys.reduce((pureObject, key) => { const value = object[key]; if ([null, undefined].includes(value)) return pureObject; return { ...pureObject, [key]: value }; }, {}); };
期望的类型转换效果:
输入类型:
{ a: number, b: null, c: undefined, }返回类型:
{ a: number }输入类型:
{ [key: string]?: string | undefined | null }返回类型(二选一均可):
{ [key: string]?: string }或
{ [key: string]: string }
解决方案
1. 定义核心类型 PurifyObject<T>
针对明确键的对象和索引签名对象两种场景,分别处理后合并逻辑:
// 处理明确键的对象:移除值为null/undefined的键 type PurifyExactObject<T> = { [K in keyof T as T[K] extends null | undefined ? never : K]: T[K] }; // 处理索引签名对象:保留签名但移除null/undefined类型 type PurifyIndexSignature<T> = T extends { [key: string]: infer U } ? { [key: string]: Exclude<U, null | undefined> } : T extends { [key: number]: infer U } ? { [key: number]: Exclude<U, null | undefined> } : T; // 合并两种场景的最终类型 type PurifyObject<T> = T extends Record<string | number, unknown> ? keyof T extends string | number ? PurifyExactObject<T> extends infer ExactResult ? ExactResult extends Record<string | number, never> ? PurifyIndexSignature<T> : ExactResult : never : never : T;
2. 修正函数泛型与实现
将原函数的返回类型替换为PurifyObject<T>,同时调整初始值的类型断言:
export const purifyObject = <T extends Record<string, unknown>>( object: T, ): PurifyObject<T> => { const keys = Object.keys(object) as (keyof T)[]; return keys.reduce((pureObject, key) => { const value = object[key]; if (value === null || value === undefined) return pureObject; return { ...pureObject, [key]: value }; }, {} as PurifyObject<T>); };
类型说明
- PurifyExactObject
:通过条件映射语法,直接排除值类型为 null或undefined的键。 - PurifyIndexSignature
:针对索引签名对象,使用 Exclude工具类型移除值类型中的null和undefined。 - PurifyObject
:优先处理明确键的对象;如果处理结果为空对象(说明输入是纯索引签名),则切换到索引签名的处理逻辑。
验证示例
const dirtyObject = { a: 1, b: null, c: undefined, }; const pureObj = purifyObject(dirtyObject); // pureObj 类型为 { a: number } const indexObj: { [key: string]: string | null | undefined } = { foo: "bar", baz: null, qux: undefined }; const pureIndexObj = purifyObject(indexObj); // pureIndexObj 类型为 { [key: string]: string }
内容的提问来源于stack exchange,提问作者Gergő Horváth
相关产品推荐
相关产品推荐

