🅰️

Typescript でオブジェクトの undefined の値を消す

2023/11/22に公開1

概要

TypeScript でオブジェクトのプロパティをフィルタリングするための関数です。
より一般的な filterProperties という関数をまず作成しました。
関数 filterUndefinedProperties は特化した関数で、与えられたオブジェクトから undefined の値を持つプロパティを除外します。

プロパティのフィルタリングの後で type assertion をして Partial<T> を返します。

実装

export const filterProperties = <T extends object>(
  obj: T,
  filterFn: (key: string, value: unknown) => boolean,
): Partial<T> => {
  return Object.fromEntries(
    Object.entries(obj).filter(([key, value]) => filterFn(key, value)),
  ) as Partial<T>;
};

export const filterUndefinedProperties = <T extends object>(
  obj: T,
): Partial<T> => filterProperties(obj, (_key, value) => value !== undefined);

実行例

https://codesandbox.io/embed/tqpk94?view=Editor+%2B+Preview&module=%2Findex.ts

Discussion

nap5nap5

ぼくも少し方針を変えてJsonCompat[ible]なアプローチでチャレンジしてみました。

定義側

import { construct } from 'radash'
import { walker } from 'obj-walker'
import { PartialDeep } from 'type-fest'

export type DeepPartial<T extends object> = PartialDeep<T, { recurseIntoArrays: true }>

export const deepOmitUndefined = <T extends object>(inputData: T, outputData: DeepPartial<T>): DeepPartial<T> => {
  walker(inputData, (d) => {
    if (d.key == null) return d
    if (!d.isLeaf) return d
    const key = d.path.join(".")
    Object.assign(outputData, { [key]: d.val })
  }, { jsonCompat: true })
  return construct(outputData) as DeepPartial<T>
}

使用側

import { describe, test, expect } from "vitest";
import { DeepPartial, deepOmitUndefined } from ".";

describe("deepOmitUndefined", () => {
  test("Example", () => {
    type Fruit = {
      id: number;
      name: string;
      price?: number | null;
      location: {
        id: number;
        name: string;
        city?: string | null;
      };
    };

    const inputData: Fruit = {
      id: 1,
      name: "Apple",
      price: undefined,
      location: {
        id: 1,
        name: "France",
        city: null,
      },
    };

    const outputData: DeepPartial<Fruit> = deepOmitUndefined(inputData, {});

    expect(outputData).toStrictEqual({
      id: 1,
      name: "Apple",
      location: { id: 1, name: "France", city: null },
    });
  });
});

demo code.

https://codesandbox.io/p/devbox/loving-maxwell-h6wv4n?file=%2Fsrc%2Findex.ts%3A1%2C1