You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:40:23