Search code examples
typescriptdiscriminated-union

type operator for removing from a tagged union


Is it possible to remove a specific type literal from a tagged union / discriminated union? How would I write such a type?

Given this type:

type MyUnion = {
  kind: "foo"
  foo: number
} | {
  kind: "bar"
  bar: string
} | {
  kind: "baz"
  baz: boolean
}

I want to remove the {kind: "baz", baz: boolean} type literal. Is it possible to write a type RemoveTag<T, K, V> such that:

type MyUnionWithoutBaz = RemoveTag<MyUnion, "kind", "baz">

yields:

type MyUnionWithoutBaz = {
  kind: "foo"
  foo: number
} | {
  kind: "bar"
  bar: string
}

?


Solution

  • You can use the Exclude<T, U> utility type to filter members from out a union T which are not assignable to another type U. Your RemoveTag type could therefore be written as

    type RemoveTag<T, K extends keyof T, V> =
      Exclude<T, Record<K, V>>
    

    depending on your use cases (if the discriminant property is optional then it wouldn't work as is). For your example, it produces:

    type MyUnionWithoutBaz = RemoveTag<MyUnion, "kind", "baz">
    /* type TWithoutBaz = {
        kind: "foo";
        foo: number;
    } | {
        kind: "bar";
        bar: string;
    } */
    

    as desired.

    Playground link to code