从 Typescript 中的联合引用复杂类型
Reference Complex type from union in 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.
也许是实用类型?
这种类型:
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'>
我正在使用 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.
也许是实用类型?
这种类型:
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'>