Home > Back-end >  How to narrow a union type?
How to narrow a union type?

Time:10-02

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;}

Playground link to code

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.

  • Related