Reputation: 15434
I want to map key/values of a type as follows:
required_key: string | undefined
to required_key: string | undefined
(same)required_key: string
to required_key: string
(same)optional_key?: string | undefined
to optional_key: string | undefined
(removed ? from key)optional_key?: string
to optional_key: string | undefined
(removed ? from key and added undefined as possible value)interface Person {
firstName: string | undefined;
middleName?: string;
lastName?: string | undefined;
}
// What I need:
// interface Person {
// firstName: string | undefined;
// middleName: string | undefined;
// lastName: string | undefined;
// }
type Normalize<T> = { [K in keyof T]-?: T[K] };
// What I get with Normalize<Person>:
// interface Person {
// firstName: string | undefined;
// middleName: string;
// lastName: string;
// }
const test: Normalize<Person> = {
firstName: undefined,
middleName: undefined, // ts err, type = string, undefined not allowed
lastName: undefined, // ts err, type = string, undefined not allowed
};
Is it possible in typescript? It seems that -?
is removing undefined from both key and value and I don't know how to add undefined value option if key is optional.
I read this Q/A Is it possible to make a property required, yet preserve undefined and I know about exactOptionalPropertyTypes
compiler flag but it still does not solve how to convert key?: string
to key: string | undefined
.
Upvotes: 1
Views: 813
Reputation: 2039
Not sure if this is the best solution, but you can achieve it with the following:
type AllOptionalKeys<T> = { [K in keyof T]-?: undefined extends T[K] ? K : never; }[keyof T];
type AllNonOptionalKeys<T> = { [K in keyof T]-?: undefined extends T[K] ? never : K; }[keyof T];
type Normalize<T> = { [K in AllOptionalKeys<T>]: T[K] | undefined } & { [K in AllNonOptionalKeys<T>]: T[K]; };
The two intermediate types allow to strip the ?
from the keys, but keep track of which are optional.
Then it constructs an union type, where all optional keys have a value of T[K] | undefined
, and all the non optional keys have T[K]
.
Upvotes: 3