TypeScript类型与GraphQL类型冲突的解决方法
GraphQL解析器TypeScript类型不兼容错误解决
问题背景
现有如下GraphQL解析器代码:
import { Resolvers } from "../../generated/schema"; export const resolvers: Resolvers = { Query: { getS: async (_parent: unknown, { id }: { id: string }): Promise<GenericResponse<S>> => { ... } } }
对应的GraphQL Schema:
type Query { getS(id: ID!): getSResponse } type S { id: ID!, wac: Float!, beginDate: String!, endDate: String!, } type getSResponse implements GenericResponse { status: Status! data: S! }
通过GraphQL Codegen生成的类型定义:
export type Resolvers<ContextType = any> = { Query?: QueryResolvers<ContextType>; } export type QueryResolvers<ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = { getS?: Resolver<Maybe<ResolversTypes['getSResponse']>, ParentType, ContextType, RequireFields<QueryGetSArgs, 'id'>>; } export type QueryGetSArgs = { id: Scalars['ID']['input']; }; export type Scalars = { ID: { input: string | number; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } };
出现的TypeScript错误:
Type '(_parent: unknown, { id }: myType) => Promise<GenericResponse<S>>' is not assignable to type 'Resolver<Maybe<ResolverTypeWrapper<GetWacPercentageResponse>>, {}, any, RequireFields<QueryGetSArgs, "id">> | undefined'. Type '(_parent: unknown, { id }: myType) => Promise<GenericResponse<S>>' is not assignable to type 'ResolverFn<Maybe<ResolverTypeWrapper<GetSResponse>>, {}, any, RequireFields<QueryGetSArgs, "id">>'. Types of parameters '__1' and 'args' are incompatible. Type 'RequireFields<QueryGetSArgs, "id">' is not assignable to type 'myType'. Types of property 'id' are incompatible. Type 'NonNullable<string | number>' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.ts(2322)
错误原因
GraphQL的ID标量类型在输入时允许string | number类型,但解析器里硬把id的类型定义为string,导致与Codegen生成的NonNullable<string | number>类型不匹配,触发类型错误。
解决方案
方案1:使用Codegen生成的参数类型
直接复用生成的QueryGetSArgs作为解析器的参数类型,无需手动定义:
import { Resolvers, QueryGetSArgs } from "../../generated/schema"; export const resolvers: Resolvers = { Query: { getS: async (_parent: unknown, { id }: QueryGetSArgs): Promise<GenericResponse<S>> => { // 若业务要求id必须为字符串,可在此处做类型转换或校验 const stringId = String(id); // 后续使用stringId处理业务逻辑 ... } } }
方案2:修改Codegen配置限制ID输入类型
如果业务场景中ID永远是字符串,可在Codegen配置文件(如codegen.ts)中自定义ID标量的输入类型:
import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { // 其他配置项... config: { scalars: { ID: 'string' } } }; export default config;
重新生成类型定义后,QueryGetSArgs中的id类型会变为string,与解析器中的定义匹配。
方案3:在解析器中处理类型兼容
若无法修改Codegen配置,可通过类型转换或断言兼容两种类型:
export const resolvers: Resolvers = { Query: { getS: async (_parent: unknown, { id }: { id: string | number }): Promise<GenericResponse<S>> => { // 转换为字符串(推荐,避免类型断言的风险) const strId = String(id); // 或使用类型断言(需确保业务逻辑能接受数字转字符串后的结果) // const strId = id as string; ... } } }
内容的提问来源于stack exchange,提问作者Owen Murphy
相关产品推荐
相关产品推荐

