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

如何在TypeScript中实现请求响应关联的泛型元组?

问题需求

实现一个请求处理函数,要求:

  • 接收特定类型的请求标识
  • 每个请求标识对应固定类型的响应参数,该参数需传入sendResponse回调函数

请求与响应的类型映射定义如下:

type OneChoice = ['123', string] | ['456', boolean];

即:

  • 请求为'123'时,sendResponse的参数必须是string类型
  • 请求为'456'时,sendResponse的参数必须是boolean类型

尝试的失败写法

我试了多种写法都没达到预期,比如下面的代码:

function handler1<T extends OneChoice>(request: T[0], sendResponse: (arg: T[1]) => void): null {
  if (request === '123') {
     sendResponse(false); // 这里本该编译失败,但实际通过了
  }
  return null;
}

后续尝试的方案(仍未解决)

按照建议尝试了以下两种写法,还是存在问题:

type OneChoiceMap = { [T in OneChoice as T[0]]: T[1] };

function handler2<K extends keyof OneChoiceMap>(request: K, sendResponse: (arg: OneChoiceMap[K]) => void): void {
  if (request === '123') {
    sendResponse('alpha'); // 报错,不符合预期!
  }
}

handler2('123', false); // 报错,符合预期
handler2('123', (arg: string) => {}); // 正常,符合预期

function handler3<K extends OneChoice[0]>(request: K, sendResponse: (arg: Extract<OneChoice, [K, any]>[1]) => void): void {
  if (request === '123') {
    sendResponse(false); // 正常通过,不符合预期!!
  }
}

handler3('123', false); // 报错,符合预期
handler3('123', (arg: string) => {}); // 正常,符合预期

正确实现方案

方案1:函数重载(推荐)

通过函数重载明确每个请求标识对应的回调参数类型,TypeScript能在调用和函数内部都正确做类型检查:

// 重载签名:定义每个请求对应的参数类型
function handler(request: '123', sendResponse: (arg: string) => void): void;
function handler(request: '456', sendResponse: (arg: boolean) => void): void;
// 实现签名:处理逻辑
function handler(request: OneChoice[0], sendResponse: (arg: string | boolean) => void): void {
  if (request === '123') {
    sendResponse('valid string'); // 正常通过
    // sendResponse(false); // 编译报错,符合预期
  } else if (request === '456') {
    sendResponse(true); // 正常通过
    // sendResponse('invalid'); // 编译报错,符合预期
  }
}

// 调用测试
handler('123', (arg) => { console.log(arg.toUpperCase()); }); // arg自动推断为string
handler('456', (arg) => { console.log(arg ? 'yes' : 'no'); }); // arg自动推断为boolean
// handler('123', (arg: boolean) => {}); // 编译报错,符合预期

方案2:映射类型+类型断言

如果需要基于映射类型实现,可以结合类型断言在函数内部明确回调的类型:

type OneChoiceMap = {
  '123': string;
  '456': boolean;
};

function handler<K extends keyof OneChoiceMap>(request: K, sendResponse: (arg: OneChoiceMap[K]) => void): void {
  if (request === '123') {
    const typedSend = sendResponse as (arg: string) => void;
    typedSend('valid'); // 正常通过
    // typedSend(false); // 编译报错,符合预期
  } else if (request === '456') {
    const typedSend = sendResponse as (arg: boolean) => void;
    typedSend(true); // 正常通过
    // typedSend('invalid'); // 编译报错,符合预期
  }
}

原因说明

之前的写法失败的核心原因是:TypeScript无法在函数内部自动窄化泛型参数的具体类型。泛型K或T被视为联合类型的父类,导致回调函数的参数类型被推断为联合类型,无法约束到当前请求对应的具体类型。而函数重载通过明确的签名定义,让TypeScript能精准匹配每个请求的类型规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 14:41:45