如何用TypeScript泛型为动态生成的GraphQL查询实现正确类型
解决TypeScript识别动态生成GraphQL查询类型的问题
要让TypeScript同时识别默认查询和动态生成的查询属性,核心是通过泛型捕获数组中key的字面量类型,并基于此构造出动态属性的类型,再与默认查询类型合并。具体步骤如下:
1. 让数组的key成为字面量类型
调用generateQueries时,使用as const断言数组,让TypeScript捕获每个key的具体字面量值,而非宽泛的string类型:
const items = [{ key: 'test_1' }, { key: 'test_2' }] as const; export const QUERIES = generateQueries(items);
2. 修改函数的泛型与返回类型
调整generateQueries函数,通过泛型提取数组中key的类型,构造动态属性的类型,并与默认查询类型合并:
import { gql, DocumentNode } from '@apollo/client'; const DEFAULT_QUERY_1 = gql` query DefaultQuery1 { defaultQuery1 { ...Response } } `; interface Item { key: string; } // 定义动态查询的类型构造器 type DynamicQueries<T extends readonly Item[]> = { [K in T[number]['key'] as `MY_DYNAMIC_${Uppercase<K>}`]: DocumentNode; }; function generateQueries<T extends readonly Item[]>(items: T): typeof DEFAULT_QUERY_1 & DynamicQueries<T> { return { ...DEFAULT_QUERY_1, ...items.reduce((acc, { key }) => { return { ...acc, [`MY_DYNAMIC_${key.toUpperCase()}`]: gql` query MyDynamic${key} { myDynamic${key} { count } } ` }; }, {} as DynamicQueries<T>) // 断言累加器类型,避免TS推断为{} } as typeof DEFAULT_QUERY_1 & DynamicQueries<T>; }
3. 组件中正常使用
此时TypeScript能正确识别动态生成的属性,不再报错:
import { useQuery } from "@apollo/client"; import { QUERIES } from "./queries"; function Comp() { const { data } = useQuery(QUERIES.MY_DYNAMIC_TEST_1); // 类型校验通过 const { data: defaultData } = useQuery(QUERIES.DEFAULT_QUERY_1); // 默认查询也正常识别 }
关键原理说明
as const固定了数组元素的key为字面量类型,让TypeScript能静态分析出具体的key值;- 泛型
T extends readonly Item[]捕获了数组的具体类型,T[number]['key']提取出所有key的字面量联合类型; asMY_DYNAMIC_${Uppercase}``将每个key转换为对应的动态属性名,构造出动态查询的类型; - 通过类型交叉
&将默认查询类型与动态查询类型合并,最终返回的类型包含所有属性。
内容的提问来源于stack exchange,提问作者Lionel T
相关产品推荐
相关产品推荐

