typescript exclude optional fields from type (deep)

684 Views Asked by At

This is an expansion of this questions: typescript exclude optional fields from type

If I have a type like this:

type MyType = {
  thingOne: { id: string; name?: string };
  thingTwo?: { id: string; name?: string };
};

I want to be able to create a type that only has the required fields in the object, aswell as anything nested inside of it.

ie.

type MyRequireds = NonOptional<MyType>;
/*
{
  thingOne: { id: string };
};
*/

is it possible?

TSPlayground link with shallow NonOptional TypeScripPlayground

2

There are 2 best solutions below

2
On BEST ANSWER

With this recursive type:

type OnlyRequired<T> =
    T extends object
        ? { [K in keyof T as {} extends Pick<T, K> ? never : K]: OnlyRequired<T[K]> }
        : T;

If T is a primitive, we don't need to do anything. However if it is an object we have to go through each key and get only the ones that can't be optional (credit to @jcalz) and then recursively gets only required keys of T[K].

Note that functions need a little special handling and checking for undefined is not exhaustive or the best way to check for optional properties but it does work for your example.

Playground

0
On

For omitting optional fields from nested objects

export type OmitOptionalNested<T> = { [P in keyof Required<T> as Pick<T, P> extends Required<Pick<T, P>> ? P : never]: 
        T[P] extends (infer U)[] ? OmitOptionalNested<U>[] :
        T[P] extends object ? OmitOptionalNested<T[P]> :
        T[P] 
}

Playground

Note: linters can sometimes only show one red squiggle at a time but it will break on compile saving you headaches

For the future, you can make almost any type a nested type by using the bellow template

type Basic<T> = { [P in keyof T]: T[P] }

type Nested<T> = { [P in keyof T]: // some logic to limit keys in object 
        T[P] extends (infer U)[] ? Nested<U>[] : // handles array
        T[P] extends object ? Nested<T[P]> : // handles objects
        T[P] // Same as in Basic<T>
}