is there a way to turn an optional property like { x?: number } to required (undefinable) `{ x: undefined | number }` via map types in typescript?

Viewed 186

I have something like { y: string; x?: number }, i need to get { y: string; x: undefined | number }. Is there a way to turn the first one into the second one via map types in typescript?

2 Answers

You can get the type you want using mapped types. You can get the optional and required keys from a type as described here

type OptionalKeys<T> = { [K in keyof T]-?:
  ({} extends { [P in K]: T[K] } ? K : never)
}[keyof T]

type RequiredKeys<T> = { [K in keyof T]-?:
  ({} extends { [P in K]: T[K] } ? never : K)
}[keyof T]

type Id<T> = { [P in keyof T]: T[P]}
type OptionalToUndefined<T> = Id<{
  [K in OptionalKeys<T>]-?: T[K] | undefined  
} & { 
  [K in RequiredKeys<T>]-?: T[K] 
}>
//  { y: number | undefined; x: boolean; }
type Foo = OptionalToUndefined<{ x: boolean; y?: number }> 

I ended up using this:

type EachNonOptional<T> = { [K in keyof T]-?: T[K]; }
type EachUndefinedOrNever<T> = { [K in keyof T]: undefined extends T[K] ? undefined : never };
type EachOptionalAsUndefined<T> = { [K in keyof EachNonOptional<T>]: EachNonOptional<T>[K] | EachUndefinedOrNever<T>[K] };
declare const x: EachOptionalAsUndefined<{ x?: number; y: string}>; // {x : number | undefined; x: string; }

or EVEN SIMPLIER:

type EachNonOptional<T> = { [K in keyof T]-?: T[K]; }
type EachOptionalAsUndefined<T> = { [K in keyof EachNonOptional<T>]: T[K] };
Related