How could one narrow/split/decompose a possibly discriminated union type?
For example in the following I'd like to get the type with the kind: "bar"
from MyUnion
.
type MyUnion = { kind: "foo", foo: number } | { kind: "bar", bar: string };
// Here I want to somehow get the type { kind: "bar", bar: string } from MyUnion
type Narrowed = NarrowUnion<MyUnion, { kind: "bar" }>;
CodePudding user response:
Unless you have some use case not mentioned in the question, you can just use the provided Extract<T, U>
utility type:
type Narrowed = Extract<MyUnion, { kind: "bar" }>;
/* type Narrowed = { kind: "bar"; bar: string;}
CodePudding user response:
If one needs to extract only a single "branch", then one could use:
type NarrowUnion<Union, Match> =
ExtractOne<Union> extends Match ? ExtractOne<Union> :
SpliceOne<Union> extends never ? never :
NarrowUnion<SpliceOne<Union>, Match>
type SpliceOne<Union> = Exclude<Union, ExtractOne<Union>>
type ExtractOne<Union> = ExtractParm<UnionToSect<UnionToParm<Union>>>
type UnionToParm<U> = U extends any ? (k: U) => void : never
type UnionToSect<U> = UnionToParm<U> extends (k: infer I) => void ? I : never
type ExtractParm<F> = F extends { (a: infer A): void } ? A : never
Here NarrowUnion
will narrow the union to the last "branch" of Union
that extends Match
.
Based on this answer.