Say I have a type like this:
type T = {
a: number;
b: undefined;
};
As b
property's value is undefined, I would like to be able to assign { a: 0 }
to a variable of this type like so:
const c: T = { a: 0 };
But this result in error Property 'b' is missing in type '{ a: number; }' but required in type 'T'.
.
Is there a way to create a RemoveUndefinedValues
generic such as:
type T2 = RemoveUndefinedValues<T>; // T2 = { a: number }
Pretty much the way Omit<Type, Keys>
works, but with values instead of keys?
CodePudding user response:
If you want to remove the key, there's two ways we could go about it. We could either omit the undefined keys, or pick only the defined keys.
Here are the utility types for those:
type DefinedKeys<T> = { [K in keyof T]: T[K] extends undefined ? never : K }[keyof T];
// Can also be written as Exclude<keyof T, DefinedKeys<T>>
type UndefinedKeys<T> = { [K in keyof T]: T[K] extends undefined ? K : never }[keyof T];
And then
type MethodOne = Pick<T, DefinedKeys<T>>;
// ^? { a: number }
type MethodTwo = Omit<T, UndefinedKeys<T>>;
// ^? { a: number }
If you want to make it optional, then you can do so with an intersection of mapped types using the two utilities above:
type MakeUndefinedOptional<T> = ({
[K in DefinedKeys<T>]: T[K];
} & {
[K in UndefinedKeys<T>]?: T[K];
}) extends infer O ? { [K in keyof O]: O[K] } : never; // Only for show
type MethodThree = MakeUndefinedOptional<T>;
// ^? { a: number; b?: undefined }
The extra extends infer O
is done because TS will not show the underlying resulting type. This forces TS to "simplify" and expand the result in full.