I have a discriminated union type that differentiates types based on a string literal field. I would like to derive a mapped type that maps all of the types in the union to their corresponding discriminator literal values.
e.g.
export type Fetch = {
    type: 'fetch',
    dataType: string
};
export type Fetched<T> = {
    type: 'fetched',
    value: T
};
// union type discriminated on 'type' property
export type Action =
    | Fetch
    | Fetched<Product>;
// This produces a type 'fetch' | 'fetched'
// from the type 
type Actions = Action['type'];
// I want to produce a map type of the discriminator values to the types 
// comprising the union type but in an automated fashion similar to how I
// derived my Actions type.
// e.g.
type WhatIWant = {
    fetch: Fetch,
    fetched: Fetched<Product>
}
Is this possible in TypeScript?
With the introduction of conditional types in TypeScript 2.8, you can define a type function which, given a discriminated union and the key and value of the discriminant, produces the single relevant constituent of the union:
type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = 
  T extends Record<K, V> ? T : never
As of TypeScript 2.8, you can also use the built-in
Extractutility type to simplify the above conditional:type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = Extract<T, Record<K, V>>
And if you wanted to use that to build up a map, you can do that too:
type MapDiscriminatedUnion<T extends Record<K, string>, K extends keyof T> =
  { [V in T[K]]: DiscriminateUnion<T, K, V> };
So in your case,
type WhatIWant = MapDiscriminatedUnion<Action, 'type'>;
which, if you inspect it, is:
type WhatIWant = {
  fetch: {
    type: "fetch";
    dataType: string;
  };
  fetched: {
    type: "fetched";
    value: Product;
  };
}
as desired, I think. Hope that helps; good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With