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

如何根据输入动态调整函数参数类型?(仿TRPC实现)

实现类似TRPC的Procedure功能:根据Schema动态控制Input参数

需求概述

  • 目标:复刻TRPC中router.query和router.mutation的核心参数控制逻辑
  • 现有createProcedure方法:接收一个包含以下属性的配置对象
    • schema:可选的输入验证器,定义输入结构
    • resolver:业务处理函数,需接收包含验证后输入的对象(属性名为input)
  • 核心约束:
    • 仅当配置中传入schema时,resolver的参数才会提示存在input属性
    • 仅当配置了schema时,createProcedure返回的函数才允许传入input参数

第一次尝试代码(存在类型漏洞)

// 模拟Schema类型,简化验证逻辑
type Schema<T = unknown> = { parse: (input: unknown) => T };

declare function createProcedure<TInput>(opts: {
  schema?: Schema<TInput>;
  resolver: (args: { input?: TInput }) => Promise<unknown>;
}): (args?: { input?: TInput }) => Promise<unknown>;

// 问题1:无schema时,resolver仍能访问args.input(不应被允许)
const proc1 = createProcedure({
  resolver: async (args) => {
    console.log(args.input); // 此处错误提示缺失
    return "ok";
  },
});

// 问题2:无schema时,返回的函数仍允许传入input参数(不应被允许)
proc1({ input: "test" }); // 此处错误提示缺失

第二次尝试(使用联合类型修复)

// 模拟Schema类型
type Schema<T = unknown> = { parse: (input: unknown) => T };

// 分情况定义配置类型:有schema/无schema
type ProcedureOpts<TInput> = 
  | { 
      schema: Schema<TInput>; 
      resolver: (args: { input: TInput }) => Promise<unknown> 
    }
  | { 
      schema?: never; 
      resolver: (args: {}) => Promise<unknown> 
    };

// 分情况定义返回函数类型
type ProcedureReturn<TInput> = TInput extends never 
  ? () => Promise<unknown> 
  : (args: { input: TInput }) => Promise<unknown>;

declare function createProcedure<TInput>(opts: ProcedureOpts<TInput>): ProcedureReturn<TInput>;

// 测试:无schema场景
const proc1 = createProcedure({
  resolver: async (args) => {
    // @ts-expect-error 此处应报错:args不存在input属性
    console.log(args.input);
    return "ok";
  },
});

proc1(); // 正确:无参数
// @ts-expect-error 此处应报错:不允许传入input
proc1({ input: "test" });

// 测试:有schema场景
const stringSchema: Schema<string> = { parse: (input) => String(input) };
const proc2 = createProcedure({
  schema: stringSchema,
  resolver: async (args) => {
    console.log(args.input.toUpperCase()); // 正确:input为string类型
    return "ok";
  },
});

proc2({ input: "test" }); // 正确:必须传入input
// @ts-expect-error 此处应报错:必须传入input参数
proc2();

方案说明

通过联合类型拆分配置结构,将createProcedure的入参分为两种互斥的情况:

  1. 存在schema时:强制resolver接收带input的参数,返回的函数也要求必须传入input
  2. 不存在schema时:resolver仅接收空参数对象,返回的函数不允许传任何参数

配合条件类型动态生成返回函数的签名,确保TypeScript的类型提示严格匹配配置是否包含schema的场景,完全满足需求中的参数控制逻辑。

内容的提问来源于stack exchange,提问作者demetrius_mp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 02:03:59