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

如何从泛型箭头函数中提取泛型类型?——tRPC路由类型合并场景下的类型处理需求

如何从泛型箭头函数中提取泛型类型?——tRPC路由类型合并场景下的类型处理需求

看起来你在tRPC虚拟路由类型合并的场景里卡壳了,核心问题是怎么把原本是泛型箭头函数的tRPC_Router_Type,改成能手动指定泛型参数的类型,对吧?而且因为tRPC有些内部类型没对外导出,没法直接重写整个路由构建函数的类型定义——这个需求其实可以通过TypeScript的infer关键字轻松解决,咱们一步步来拆解:

先从你的简单类比例子入手

你给的简化版问题是:把type ArrowFn = <TInput extends string>(input: TInput) => {}转成能手动传泛型的type GenericFn<TInput extends string> = (input: TInput) => {}。这里的关键是用infer把箭头函数的泛型参数「提升」到类型本身的泛型上:

// 定义一个工具类型:把泛型箭头函数转成「类型本身带泛型」的函数类型
type ExtractGenericFn<Fn> = 
  Fn extends <TInput extends infer TConstraint>(input: TInput) => infer TReturn
    ? <T extends TConstraint>(input: T) => TReturn
    : never;

// 测试你的简化例子
type ArrowFn = <TInput extends string>(input: TInput) => { value: TInput };
// 转成可手动指定泛型的类型
type ConfigurableFn = ExtractGenericFn<ArrowFn>;
// 现在ConfigurableFn就等价于:<T extends string>(input: T) => { value: T }

// 如果要直接传入参数类型得到结果类型:
type FnResult = ReturnType<ConfigurableFn<"test">>;
// FnResult 就是 { value: "test" }

套回你的tRPC实际场景

回到你遇到的tRPC问题:你的tRPC_Router_Type是一个泛型箭头函数,而且里面包含tRPC未导出的内部类型(比如DecorateCreateRouterOptions),咱们完全不用管这些内部类型,用infer让TypeScript自动帮我们捕获它们就行:

步骤1:定义提取泛型箭头函数的工具类型

// 工具类型:把泛型箭头函数转成可手动指定泛型的函数类型
type ExtractRouterBuilder<BuilderFn> = 
  BuilderFn extends <TInput extends infer TConstraint>(input: TInput) => infer TRouter
    ? <T extends TConstraint>(input: T) => TRouter
    : never;

这里的TConstraint会自动捕获tRPC_Router_Type里泛型参数的约束(也就是CreateRouterOptions),TRouter会自动捕获路由构建后的返回类型(包括那些未导出的内部类型),完全不用我们手动写那些摸不着的内部类型定义。

步骤2:转换你的tRPC路由构建函数类型

// 你原本的泛型箭头函数类型
type tRPC_Router_Type = <TInput extends CreateRouterOptions>(input: TInput) => BuiltRouter<
  { ctx: My_tRPC_Context_Type; meta: object; errorShape: DefaultErrorShape; transformer: false; },
  DecorateCreateRouterOptions<...> // 这个未导出的类型不用管,infer会帮我们抓
>;

// 转成可手动指定泛型的路由构建器类型
type ConfigurableRouterBuilder = ExtractRouterBuilder<tRPC_Router_Type>;

步骤3:生成全局虚拟路由类型

// 你的各个服务路由类型集合
type MyServiceRoutersTypes = { 
  service1: typeof router1, 
  service2: typeof router2 
};

// 传入服务路由类型,得到合并后的全局虚拟路由类型
export type GlobalVirtualRouter = ReturnType<ConfigurableRouterBuilder<MyServiceRoutersTypes>>;

为什么这能行?

核心在于infer的「类型捕获」能力:它不需要我们知道tRPC内部未导出类型的具体结构,只需要让TypeScript帮我们完整保留这些类型信息就行。通过把泛型箭头函数的泛型参数「提升」到类型本身的泛型上,我们就能手动传入MyServiceRoutersTypes,最终得到类型安全的全局虚拟路由类型,客户端消费时就能获得完整的类型提示。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 08:03:03