4

I'm using graphql-codegen to generate types from my graphQL queries.

The result is sometimes pretty complex specifically when unions are involved.

Here is a concrete example

export type GroupQuery = { __typename?: 'Query' } & {
  group?: Maybe<
    { __typename?: 'Group' } & Pick<
      Group,
      'id' | 'name' 
    > & {
        criterions: Array<
          { __typename?: 'kindA' } & Pick<SomeModel, 'id' | 'type'> | 
          { __typename?: 'kindB' } & Pick<SomeOtherModel, 'id' | 'type' | 'count'>
        >
    }
  }

So I'm trying to do is be able to refer to a specific case of the union based on the __typename

let kindB: NonNullable<GroupQuery['group']>['criterions'][0]// not sure where to go from here.

Maybe a utility type?

1 Answer 1

4

This type:

type T = NonNullable<GroupQuery['group']>['criterions'][0]`

Would be resolved to this type:

type T = {
    __typename?: "kindA" | undefined;
    id: number;
    name: string;
} | {
    __typename?: "kindB" | undefined;
    id: number;
    name: string;
}

So what you are really asking how to get the branch of the union where:

__typename === 'kindB'

In that case you can use an intersection & to filter a union type. In general that works like this:

type T = ("A" | "B" | "C") & "A" // "A"

Playground

So you can use an intersection to make the union resolve to only the type that could match the intersected type.

type KindB =
    NonNullable<GroupQuery['group']>['criterions'][0] & { __typename: 'kindB' }

Now KindB resolves to this type:

type KindB = {
    __typename?: "kindB" | undefined;
    id: number;
    name: string;
} & {
    __typename: 'kindB';
}

As you can see, the kindA member of the union is no longer present, and the remaining member of the union is being intersected with { __typename: 'kindB' }. If you apply that intersection, it reduces to:

type KindB = {
    __typename: "kindB";
    id: number;
    name: string;
}

Playground with working code


With some refactoring, you could even make this quite nice with a nice generic type alias:

// Union of all criterion types
type GroupQueryCriterions =
    NonNullable<GroupQuery['group']>['criterions'][number]

// Get the branch of the criterions union that has a specific typename.
type GroupQueryCriterionType<T extends GroupQueryCriterions['__typename']> =
    GroupQueryCriterions & { __typename: T }

// Get a specific criterion type.
type KindB = GroupQueryCriterionType<'kindB'>

Playground

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.