DEV Community

Frédéric Leroy
Frédéric Leroy

Posted on

Typescript type grouping a union type of objects by any property discriminating these objects.

MappingByDiscriminator

Example:

type Car = {
  kind: "car",
  ...
};

type Truck = {
  kind: "truck",
  ...
};

type Vehicle = Car | Truck;
Enter fullscreen mode Exit fullscreen mode

Then

type VehiclesByKind = MappingByDiscriminator<Vehicle,"kind">;
Enter fullscreen mode Exit fullscreen mode

Will produce :

type VehiclesByKind = {
    car: Car[],
    truck: Truck[],
}
Enter fullscreen mode Exit fullscreen mode

Mapping union type on discriminator
using the UnionMemberByDiscriminator and GetProperty described below,

type MappingByDiscriminator< E extends object, D extends keyof E > = 
   GetPropertyType<E,D> extends string | number ?
   {
      [d in GetPropertyType<E, D>]: UnionMemberByDiscriminator<E, D, d>[];
    }
  : never;
Enter fullscreen mode Exit fullscreen mode

Will map types in a union by a discriminator.

GetProperty

Get the type of an object property with generics

type GetProperty<E extends object, P extends keyof E> = 
  E extends { [key in P]: infer V } ? V : never;
Enter fullscreen mode Exit fullscreen mode

Example:

type Entity = {
   kind: 'human' | 'animal',
   size: 'microscopic' | 'small' | 'big' | 'giant',
}
Enter fullscreen mode Exit fullscreen mode

Then

type SizeType = GetProperty<Entity,"size">
Enter fullscreen mode Exit fullscreen mode

Will produce

type SizeType = 'microscopic' | 'small' | 'big' | 'giant';
Enter fullscreen mode Exit fullscreen mode

UnionMemberByDiscriminator

Extract a specific type from a union for a given discriminator value (can be used with generics)

type UnionMemberByDiscriminator<
  E extends object,
  D extends keyof E,
  DValue extends string | number
> = E extends {[key in D]:DValue} ? E : never;
Enter fullscreen mode Exit fullscreen mode

Example:

type Car = {
  kind: "car",
  ...
};

type Truck = {
  kind: "truck",
  ...
};

type Vehicle = Car | Truck;

type InferredCar = 
   UnionMemberByDiscriminator<Vehicle, "kind", "car">
Enter fullscreen mode Exit fullscreen mode

Will produce

type InferredCar = Car;
Enter fullscreen mode Exit fullscreen mode

This is useful in a generic context (see above)

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more →

Top comments (0)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay