Search code examples
javascripttypescriptnullundefined

Remove null attributes from an Object in Typescript


As reference Remove blank attributes from an Object in Javascript, how to make it Typescript compatible?

JS function (nested objects | ES10):

function removeEmpty(obj) {
  return Object.fromEntries(
    Object.entries(obj)
      .filter(([_, v]) => v != null)
      .map(([k, v]) => [k, v === Object(v) ? removeEmpty(v) : v])
  );
}

I've tried with Exclude<T, null> but it doesn't works with nested objects and I think it's not the correct utility to use.

Note that the returned type should remove null type(s) but keeps undefined.

Example/Expected behaviour:

type TestType = {
  a?: {
    b?: {
      c: string;
    } | null;
    z?: {
      x: string;
    };
  } | null;
};

const testObj: TestType = {
  a: {
    b: null,
    z: { x: 'Hi' }
  }
};

const resultObj = removeEmpty(testObj);

Where resultObj type is similar to:

type ResultTestTypeExample = {
  a?: {
    b?: {
      c: string;
    };
    z?: {
      x: string;
    };
  };
};

Solution

  • Does this work for you?

    type ExpandRecursively<T> = T extends object
      ? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
      : T;
    
    type RemoveNull<T> = ExpandRecursively<{ [K in keyof T]: Exclude<RemoveNull<T[K]>, null> }>
    

    Usage:

    function removeEmpty<T>(obj: T): RemoveNull<T> {
      return Object.fromEntries(
        Object.entries(obj)
          .filter(([_, v]) => v != null)
          .map(([k, v]) => [k, v === Object(v) ? removeEmpty(v) : v])
      ) as RemoveNull<T>
    }
    

    Playground