You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 13:36:22