I have a disciminated union
type MyDUnion = { type: "anon"; name: string } | { type: "google"; idToken: string };
I want to access the name key from the discriminative union, from the MyDUnion
type directly. Something like this
type Name = MyDUnion['name']
But typescript won't allow that
Property 'name' doesn't exist on type '{ type: "anon"; name: string } | { type: "google"; idToken: string }'
How can I access it?
To be clear, this is not a valid solution:
type MyName = string;
type MyDUnion = { type: "anon"; name: MyName } | { type: "google"; idToken: string };
type Name = MyName; // this line would be in a different file
This is not valid, because then I would have to export both MyName
and MyDUnion
types to be used elsewhere.
Any ideas?
CodePudding user response:
In order to filter union of objects, usually you need to use Extract: The easy way:
type Result = Extract<MyDUnion , {type: "anon"}>
The more robust:
type MyDUnion = { type: "anon"; name: string } | { type: "google"; idToken: string };
type Values<T> = T[keyof T]
type Filter<Union, Type extends Partial<Union>> = Extract<Union, Type>
type Result = Filter<MyDUnion, { type: 'anon' }>
CodePudding user response:
In order to get the required key, you have to somehow tell the Typescript compiler
Hey compiler, I want to know about this object, under a very specific case
In this case, you want to know about the object, when the type ==='anon'
. So, taking your example,
type MyDUnion = { type: "anon"; name: string } | { type: "google"; idToken: string };
type SpclCase = MyDUnion & {type: "anon"}
By doing so, you're getting information about when theses two cases overlap. Now you can just index the name
key directly.
type Name = SpclCase['name']
If you want to make this more robust, we can make sure that the narrowing type we use ({type: 'anon'}
in this case), satisfies the required shape. Here's a little impromptu solution for that.
type DiscriminatorObj = { type: 'anon' }
type RequiredCase = DiscriminatorObj extends Pick<MyDUnion, "type"> ? DiscriminatorObj: never;
type SpclCase = (RequestBody & RequiredCase);
type Name = SpclCase['name']
I know its a little rough around the edges, but you can always extract this into generic functions and use them as you please. I merely showed you the fundamental logic. You can use it to make it more aesthetically pleasing.