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

TypeScript中如何正确定义多层泛型类型的请求数组参数?

解决方案:用联合类型实现多类型请求数组的类型约束

要让send函数接收不同服务、不同方法的Request实例数组,同时保留类型检查,核心是生成所有合法Request类型的联合类型,而非用单一泛型或错误的交叉类型。

步骤1:定义辅助联合类型

先创建一个辅助类型,自动生成TServiceMap下所有合法的Request组合:

export type ServiceMap<T> = { [K in keyof T]: MethodMap<T[K]> }
export type MethodMap<T> = { [K in keyof T]: (...args: any) => Promise<any> }

interface Request<TServiceMap extends ServiceMap<TServiceMap>, TService extends keyof TServiceMap, TMethod extends keyof TServiceMap[TService]> {
    service: TService,
    method: TMethod,
    // 其他字段
}

// 辅助类型:生成所有合法Request的联合类型
type AnyRequest<TServiceMap extends ServiceMap<TServiceMap>> = {
  [ServiceKey in keyof TServiceMap]: Request<TServiceMap, ServiceKey, keyof TServiceMap[ServiceKey]>
}[keyof TServiceMap];

这个类型的逻辑是:遍历TServiceMap的每个服务键,生成该服务对应的所有Request类型,最后通过[keyof TServiceMap]提取所有类型的联合。

步骤2:重构send函数

用辅助联合类型约束请求数组:

function createRequest<TServiceMap extends ServiceMap<TServiceMap>, TService extends keyof TServiceMap, TMethod extends keyof TServiceMap[TService]>(service: TService, method: TMethod): Request<TServiceMap, TService, TMethod> {
    return {} as Request<TServiceMap, TService, TMethod>;
}

function send<TServiceMap extends ServiceMap<TServiceMap>>(requests: AnyRequest<TServiceMap>[]): void {
    // 实现发送逻辑
}

验证示例

用你的测试代码验证,类型检查会正常工作:

interface UserService {
    login: (userName: string) => Promise<string>,
    logout: () => Promise<void>
}

interface TicketService {
    create: (ticketNumber: number) => Promise<void>
}

interface MyServices {
    user: UserService,
    ticket: TicketService,
}

const requests = [
    createRequest<MyServices, 'user', 'login'>('user', 'login'),
    createRequest<MyServices, 'ticket', 'create'>('ticket', 'create')
]

send<MyServices>(requests); // 类型检查通过

// 错误示例:传入不存在的方法会触发类型报错
const invalidRequests = [
    createRequest<MyServices, 'user', 'create'>('user', 'create') // 报错:'create'不是UserService的方法
]

为什么之前的写法失败?

  • 第一种泛型写法:TService和TMethod是全局泛型,会强制数组中所有元素的服务和方法类型完全一致,不符合多请求场景。
  • 第二种写法:keyof TServiceMap[keyof TServiceMap]是所有服务方法名的交叉联合,没有绑定到具体服务,TypeScript无法找到同时属于所有服务的方法,因此推断为never。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:55:19