André Krosby
André Krosby

Reputation: 1146

Typescript return object without null or undefined values

We are using a cleanNullOrUndefined function in our codebase, which gets rid of keys in an object if the value of the key is null or undefined. This is not well-typed and just returns a Partial of the original object which gives some errors in other places.

What we need is to type the function to return the object, with keys that are null or undefined removed and inferred types for the other keys.

Example:

const obj = {
  a: 1,
  b: 'string',
  c: false,
  d: null,
  e: undefined
}

// Desired return type

interface ReturnType {
  a: number,
  b: string,
  c: boolean
}

I can't seem to get my head around how to do this.

Upvotes: 3

Views: 3886

Answers (2)

Consider this example:

const obj = {
  a: 1,
  b: 'string',
  c: false,
  d: null,
  e: undefined
}

type Validate<T> = Pick<T, {
  [Prop in keyof T]: T[Prop] extends null | undefined ? never : Prop
}[keyof T]>;

// type Test = {
//     a: 1;
//     b: 'string';
//     c: false;
// }
type Test = Validate<{
  a: 1,
  b: 'string',
  c: false,
  d: null,
  e: undefined
}>

const util = <Obj,>(obj: Obj): Validate<Obj> => {
  return 'NOT IMPLEMENTED' as any
}

const result = util({
  a: 1,
  b: 'string',
  c: false,
  d: null,
  e: undefined
})

result.a // ok
result.e // error

Playground

Validate iterates through each object key and checks whether it extends null | undefined or not. If yes - return never, otherwise - return key name Prop. [keyof T] - at the and grabs all values from newly created object. Pick - in turn obtains again only valid keys from T.

Upvotes: 5

vitaly-t
vitaly-t

Reputation: 25830

The following is probably half the answer. I wanted to show that you can get the destination object with just one line (chain) of code:

const obj = {
  a: 1,
  b: 'string',
  c: false,
  d: null,
  e: undefined
};

const dest = Object.keys(obj)
    .filter(a => obj[a] !== null && obj[a] !== undefined)
    .reduce((c, a) => { c[a] = obj[a]; return c; }, {});

console.log(dest);

But there might be a lot more, just to make the resulting type inferred correctly. The question is - do you really need it? ;)

Upvotes: 0

Related Questions