Ссылка на сложный тип из объединения в Typescript
Я использую graphql-codegen
для генерации типов из моих запросов graphQL.
Результат иногда бывает довольно сложным, особенно когда unions
вовлечены.
Вот конкретный пример
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'>
>
}
}
Поэтому я пытаюсь сослаться на конкретный случай союза на основе __typename
let kindB: NonNullable<GroupQuery['group']>['criterions'][0]// not sure where to go from here.
Может утилитка типа?
1 ответ
Этот тип:
type T = NonNullable<GroupQuery['group']>['criterions'][0]`
Были бы разрешены к этому типу:
type T = {
__typename?: "kindA" | undefined;
id: number;
name: string;
} | {
__typename?: "kindB" | undefined;
id: number;
name: string;
}
Итак, что вы на самом деле спрашиваете, как получить филиал союза, где:
__typename === 'kindB'
В этом случае вы можете использовать перекресток &
для фильтрации типа объединения. Обычно это работает так:
type T = ("A" | "B" | "C") & "A" // "A"
Таким образом, вы можете использовать пересечение, чтобы объединение разрешалось только к типу, который может соответствовать пересеченному типу.
type KindB =
NonNullable<GroupQuery['group']>['criterions'][0] & { __typename: 'kindB' }
Сейчас же KindB
разрешается к этому типу:
type KindB = {
__typename?: "kindB" | undefined;
id: number;
name: string;
} & {
__typename: 'kindB';
}
Как видите, kindA
члена союза больше нет, а оставшийся член союза пересекается с { __typename: 'kindB' }
. Если вы примените это пересечение, оно уменьшится до:
type KindB = {
__typename: "kindB";
id: number;
name: string;
}
С помощью некоторого рефакторинга вы даже можете сделать это весьма неплохо с помощью красивого псевдонима универсального типа:
// 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'>