Home > other >  Get a type from a Union based on string property
Get a type from a Union based on string property

Time:03-16

Given the type:

type Invitation =
  | {
      __typename?: 'ClientInvitation'
      email: string
      hash: string
      organizationName: string
    }
  | {
      __typename?: 'ExpertInvitation'
      email: string
      hash: string
      expertName: string
    }

how can I infer one of the types?

For example:

type ClientInvitation = SomeTypeUtil['ClientInvitation']

should make ClientInvitation have:

    {
      __typename?: 'ClientInvitation'
      email: string
      hash: string
      organizationName: string
    }

CodePudding user response:

The easiest way to do this is probably to use a mapped type with renamed keys like this:

type InvitationMap = { [T in Invitation as NonNullable<T['__typename']>]: T }

Here we are iterating the type T over the union members of Invitation. For each such member T we want the property value to be T, and we want the property key to be the string literal type of T's __typename property. That would just be T['__typename'] using indexed access, but that doesn't quite work. Because the __typename property is optional, the property type will include undefined (like 'ClientInvitation' | undefined or 'ExpertInvitation' | undefined). To remove undefined quickly we can use the NonNullable<T> utility type.

Let's look at the IntelliSense quick info for the InvitationMap type:

/* type InvitationMap = {
    ClientInvitation: {
        __typename?: "ClientInvitation" | undefined;
        email: string;
        hash: string;
        organizationName: string;
    };
    ExpertInvitation: {
        __typename?: "ExpertInvitation" | undefined;
        email: string;
        hash: string;
        expertName: string;
    };
} */

Now that we have InvitationMap, we can just index into it with the desired key:

type ClientInvitation = InvitationMap['ClientInvitation'];
/* type ClientInvitation = {
    __typename?: "ClientInvitation" | undefined;
    email: string;
    hash: string;
    organizationName: string;
} */

Playground link to code

  • Related