Home > Enterprise >  How to write a type that transforms T object into the same object excluding null, and undefined?
How to write a type that transforms T object into the same object excluding null, and undefined?

Time:01-14

This is what I've tried so far:


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 };
  }, {});
};

TS playground.

const dirtyObject = {
    a: 1,
    b: null,
    c: undefined,
};
console.log(purifyObject(dirtyObject)); // { a: 1 }

I'm trying to get an object which can have values null, or undefined, and returns the type of the same object excluding the key-value pairs with values null, and undefined. How to write the type for that?

Following the above example:

{
    a: number,
    b: null,
    c: undefined,
}

Should return

{ a: number }
{ [key: string]?: string | undefined | null } 

Should return

{ [key: string]?: string }

or

{ [key: string]: string }

CodePudding user response:

You can use a mapped type with an as clause to exclude keys that contain null or undefined

type PurifyObject<T> ={ [P in keyof T as T[P] extends null | undefined ? never : P]: T[P] }

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] as never;

    if ([null, undefined].includes(value)) return pureObject;

    return { ...pureObject, [key]: value };
  }, {} as PurifyObject<T>);
};

Playground Link

CodePudding user response:

Typescript playground link

First you need build an union of keys which contains dirty value like so:

/**
 * Build an union of keys which contains dirty value
 */
type DirtyKeys <Object extends Record<string,unknown>> = {
  [key in keyof Object]: Object[key] extends null | undefined ? key : never;
}[keyof Object];

Then you can exclude these keys and use mapped types to build a new type like so:

/**
 * Map the type to new type excluding dirty keys from `keyof Object` which does not contain null or undefined as value
 * Nested Objects are supported too
 */

type Purify<Object extends Record<string,unknown>> = {
  [key in Exclude<keyof Object, DirtyKeys<Object>>]: Object[key] extends Record<string,unknown>
    ? Purify<Object[key]> 
    : Object[key]
}
  • Related