I've got one union type that is constructed from object keys, which may contain string, number, and boolean keys.
Example:
type Example = "true" | "semi" | "false";
What I want to achieve is to get a new type, which replaces strings true
or false
with actual boolean values.
type Example = true | "semi" | false;
Converting directly to boolean won't work since there might be cases where I don't have either true
or false
This is what I've tried
type ReplaceTrue<T> = Extract<T, "true"> extends never ? T : Exclude<T, "true"> | true;
type ReplaceFalse<T> = Extract<T, "false"> extends never ? T : Exclude<T, "false"> | false;
type PickMyType<T> = ReplaceBoolean<T, "true", true> | ReplaceBoolean<T, "false", false>
I've also tried combining ReplaceTrue
and ReplaceFalse
to a single type, but I think that this would lead to a more unreadable code.
However, I feel like these solutions are not elegant and I'm wondering if there is any other method of replacing them.
CodePudding user response:
Using a mapping type:
type T1 = "true" | "semi" | "false";
type Mapping = { true: true; false: false };
type T2 = Mapping[T1 & keyof Mapping] | Exclude<T1, keyof Mapping>;
// T2 = boolean | "semi"
CodePudding user response:
This is achievable by a straightforward distributive conditional type:
type ReplBool<T> = T extends "true" ? true : T extends "false" ? false : T;
type Example = "true" | "semi" | "false";
type ReplacedExample = ReplBool<Example>;
// type ReplacedExample = boolean | "semi"
// note that boolean is an alias for true | false
You can do more complicated things involving mapped lookups or nested utility types, but the above definition is probably the tersest definition for something with just two cases.