use*_*925 11 typescript typescript-generics graphql-codegen
更新:最小示例代码复制
我有自动生成的代码(Graphql-Codegen),可以生成以下类型。为了简单起见,我将其压缩了。
export type AccessControlList = {
__typename?: 'AccessControlList';
id: Scalars['Int'];
subscriber: Scalars['Int'];
subscriberRel: MasterSubscriberData;
};
export type Query = {
__typename?: 'Query';
workOrders: Array<WorkOrdersGroupBy>;
viewer: AccessControlAccounts;
};
Run Code Online (Sandbox Code Playgroud)
由于我只对此示例的查看器感兴趣,因此我使用 Typescript Pick 选择它
export type ViewerType = Pick<Query, 'viewer'>;
Run Code Online (Sandbox Code Playgroud)
它还会自动为需要 AccessControlAccounts 中某些但不是所有可能字段的查询生成专用类型,并且我需要的字段也有所不同。我在这里省略了 MasterSubscriberData 的类型定义,但可以在下面推断出来(但本示例并不真正需要)
不同的查询需要访问查询结构的不同部分,因此为每个不同的查询生成不同的类型,例如
export type LeadSourcesQuery =
{ __typename?: 'Query',
viewer: { __typename?: 'AccessControlAccounts',
AccessControlList: Array<{ __typename?: 'AccessControlList',
subscriberRel: { __typename?: 'MasterSubscriberData',
LeadSources: Array<{ __typename?:
'LeadSources', id: number> }
}>
}
};
Run Code Online (Sandbox Code Playgroud)
我正在尝试创建一个通用函数,它可以返回对常用访问的深层嵌套对象的引用,而不管传递的子查询类型如何(例如LeadSourcesQuery等)。我想出的方法可以在运行时运行,但无法通过 Typescript 静态检查。
// expected subscriberRel return type
type SubRetType<T extends ViewerType> =
T["viewer"]["AccessControlList"][number]["subscriberRel"];
// returning a reference to subscriberRel to avoid doing this nesting everywhere
export const subscriber = <T extends ViewerType>(
result: T | undefined
): SubRetType<T> | undefined => {
if (!result) return undefined;
return result.viewer?.AccessControlList.at(0)?.subscriberRel;
};
Run Code Online (Sandbox Code Playgroud)
每当我在 src 中调用此代码时,我都会收到以下 Typescript 错误,我知道这与类型兼容性有关。
类型为“ListCustomerTypesQuery |”的参数 未定义' 不可分配给'ViewerType | 类型的参数 undefined'.ts(2345) 属性“viewer”的类型不兼容。...AccessControlAccounts 类型缺少以下属性
我只是不确定如何帮助 Typescript 理解无论T我传递什么,它都将始终是Query. 但是,由于不使用extendssuper-type Query,Typescript 无法理解 AccessControlList.subscriberRel 的嵌套字段在“编译时”存在。并且专门的泛型类型T并没有真正扩展超类型Query。
每当我不使用泛型时,我都可以使用,例如Extract<Query, ListCustomerTypesQuery>提取公共属性,但这并不会使错误在我使用泛型时消失Extract<Query, T>。
我可以通过将其强制转换来解决此错误,但我不想对单个函数调用执行此操作。
subscriber(result.value as ViewerType);
Run Code Online (Sandbox Code Playgroud)
我更愿意清理它并保持它简单
subscriber(result.value);
Run Code Online (Sandbox Code Playgroud)
的任何子类型Query听起来都像是 的任务DeepPartial。您想要任何可能的子类型,Query这意味着它的所有属性都是可选的。这是DeepPartial:
type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;
Run Code Online (Sandbox Code Playgroud)
您可能还需要使其适用于数组。
然后我们更改 的签名subscriber以获取 的深度部分ViewerType:
export const subscriber = <T extends ViewerType>(
result: DeepPartial<T> | undefined /** Extract<ViewerType,T> doesn't work either */
): SubRetType<T> | undefined => {
Run Code Online (Sandbox Code Playgroud)
不幸的是,您仍然需要转换最后一个返回值,因为 TypeScript 不明白您只需要子类型:
return result.viewer?.AccessControlList?.at(0)?.subscriberRel as SubRetType<T>;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1915 次 |
| 最近记录: |