Given a discriminated union type like this:
type HomeRoute = { name: 'Home' };
type PageRoute = { name: 'Page'; id: number };
type SearchRoute = { name: 'Search'; text: string; limit?: number };
type Route = HomeRoute | PageRoute | SearchRoute;
I would like an utility type that takes the union type and its the discriminant (here the type of the name member: "Home" | "Page" | "Search"
) and returns the matching case:
type Discriminate<TUnion, TDiscriminant> = ???
type TestHome = Discriminate<Route, 'Home'>; // Expecting "HomeRoute" (structure)
type TestPage = Discriminate<Route, 'Page'>; // Expecting "PageRoute" (structure)
You can use the Extract
predefined conditional type:
type HomeRoute = { name: 'Home' };
type PageRoute = { name: 'Page'; id: number };
type SearchRoute = { name: 'Search'; text: string; limit?: number };
type Route = HomeRoute | PageRoute | SearchRoute;
type TestHome = Extract<Route, { name: 'Home' }>;
type TestPage = Extract<Route, { name: 'Page' }>;
You can also create a generic version of Discriminate
but not sure if it is worth it as you would need the field as well:
type Discriminate<TUnion, TField extends PropertyKey, TDiscriminant> = Extract<TUnion, Record<TField, TDiscriminant>>
type TestHome = Discriminate<Route, 'name', 'Home'>; // Expecting "HomeRoute" (structure)
type TestPage = Discriminate<Route, 'name', 'Page'>; // Expecting "PageRoute" (structure)
The most verbose solution would be:
type Discriminate<TUnion, TDiscriminant> =
TUnion extends {name: TDiscriminant} ? TUnion : never
type HomeMember = Discriminate<Route, 'Home'>;
type PageMember = Discriminate<Route, 'Page'>;
We can use also existing utility type Extract which will do conditional type for use:
type Discriminate<TUnion, TDiscriminant> = Extract<TUnion, {name: TDiscriminant}>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.