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

如何关联TypeScript函数参数类型(泛型、联合类型、元组)

问题:创建类型安全的WebEvent构造函数

给定以下TypeScript枚举和元组联合类型:

enum EventType { A, B };

type WebEvent =
  [id: string, type: EventType.A, timestamp: number, payload: string] |
  [id: string, type: EventType.B, timestamp: number, payload: number];

需要实现一个构造函数,接收type和payload两个参数,要求payload的类型必须与type对应的WebEvent元组分支匹配,且返回值为WebEvent类型。

现有实现如下:

function create<T extends WebEvent>(type: T[1], payload: T[3]) {
  const event = [crypto.randomUUID(), type, Date.now(), payload] as const;

  return event;
}

该实现存在两个问题:

  1. 返回值类型为readonly [string, T[1], number, T[3]],并非预期的WebEvent类型;
  2. 无法拦截非法的类型混合调用,比如:
    create(EventType.A, 42); // 应为非法但未报错
    create(EventType.B, 'hey'); // 应为非法但未报错
    

解决方案

方案1:利用映射类型自动关联类型

从WebEvent中自动推导EventType与对应payload类型的映射关系,通过泛型约束实现类型安全:

// 自动从WebEvent中提取EventType和payload的对应关系
type EventPayloadMap = {
  [E in WebEvent as E[1]]: E[3]
};

function create<T extends EventType>(type: T, payload: EventPayloadMap[T]): WebEvent {
  const event = [crypto.randomUUID(), type, Date.now(), payload] as const;
  // 已确保type和payload匹配,安全断言为WebEvent
  return event as WebEvent;
}

方案2:函数重载(适合分支较少的场景)

为每个WebEvent分支定义函数重载,明确合法的参数组合:

// 重载签名:定义合法的参数类型组合
function create(type: EventType.A, payload: string): WebEvent;
function create(type: EventType.B, payload: number): WebEvent;

// 实现签名:处理通用逻辑
function create(type: EventType, payload: string | number): WebEvent {
  return [crypto.randomUUID(), type, Date.now(), payload] as WebEvent;
}

验证效果

两种方案都能实现严格的类型检查:

create(EventType.A, 'hey'); // ✅ 合法
create(EventType.B, 42); // ✅ 合法
create(EventType.A, 42); // ❌ 报错:类型“number”不能赋给类型“string”
create(EventType.B, 'hey'); // ❌ 报错:类型“string”不能赋给类型“number”

方案选择

  • 若WebEvent分支较多,优先用映射类型,无需手动维护多个重载,扩展性更好;
  • 若分支较少,函数重载可读性更强,逻辑更直观。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 16:45:12