TypeScript中如何为包装函数正确推断参数类型
问题:TypeScript泛型自动推断函数参数时的元组与对象类型不匹配
你想用泛型自动推断模型函数的参数类型作为GraphQL resolver的args类型,但ModelArguments返回了元组类型,导致无法直接访问args.userID,出现TS2339错误——尽管运行时args确实是对象。
问题代码
/** * Model instances * @description These are the instances of the models that will be used to interact with the database. */ const models = { session: Session(prisma.session), user: User(prisma.user) } /** * A type for the arguments of resolver functions */ type ModelArguments< M extends keyof typeof models, T extends keyof { [P in keyof typeof models[M] as ( typeof models[M][P] extends Function ? P : never )] : never } > = Parameters<typeof models[M][T]> /** * GraphQL resolvers * @description This is the object that will contain the resolvers for the queries defined in the schema. */ const resolvers = { Query: { user: async (p, args: ModelArguments<"user", "get">) => { console.log(args); // {"userID": "<user-id>"} return await models.user.get(args.userID) // TS2339: Property userID does not exist on type [userID?: string] } }, };
问题原因
Parameters<T>工具类型会将函数的参数列表转换为元组类型。你的models.user.get函数接收一个对象参数,所以Parameters<typeof models.user.get>返回的是[{userID?: string}]——一个包含对象的元组。但GraphQL resolver的args是这个对象本身,不是元组,因此类型不匹配,TypeScript不允许你在元组上访问userID属性。
解决方案
修改ModelArguments类型,直接提取元组的第一个元素(也就是模型函数接收的对象参数):
type ModelArguments< M extends keyof typeof models, T extends keyof { [P in keyof typeof models[M] as (typeof models[M][P] extends Function ? P : never)]: never } > = Parameters<typeof models[M][T]>[0]; // 取元组的第一个元素,匹配args的对象类型
修改后,ModelArguments<"user", "get">会直接推断为{userID?: string},和resolver的args类型完全匹配。此时你可以正常访问args.userID,或者直接将args传入模型函数:
const resolvers = { Query: { user: async (p, args: ModelArguments<"user", "get">) => { console.log(args); // {"userID": "<user-id>"} // 两种写法都可行: return await models.user.get(args.userID); // 或者直接传入整个args对象(如果模型函数原本就接收对象参数) // return await models.user.get(args); } }, };
扩展说明
如果你的模型函数存在接收多个参数的情况,可以进一步调整ModelArguments,将元组转换为键值对对象。但从你的场景来看,GraphQL resolver的args始终是单个对象,所以提取元组第一个元素的方案足够解决问题。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

