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

TypeScript泛型优化:实现trackEvent参数按需必填

解决方案

可以通过泛型条件类型结合剩余参数实现需求,让第二个参数在事件对应值为undefined时可选,其他情况必填。

实现代码

export type Events = {
  LOGIN: undefined
  NAVIGATION: {
    screen: string
  }
  SUPPORT: {
    communication_method: 'chat' | 'email' | 'phone'
  }
}

export function trackEvent<K extends keyof Events>(
  eventName: K,
  ...args: Events[K] extends undefined ? [] : [eventValues: Events[K]]
) {
  const eventValues = args[0] as Events[K];
  if (Platform.OS === 'web') return;
  logEvent(eventName, eventValues ?? {});
}

// 测试用例
trackEvent('LOGIN') // ✅ 无TS错误
trackEvent('LOGIN', undefined) // ✅ 仍支持传undefined
trackEvent('SUPPORT') // ❌ TS错误:缺少第二个参数
trackEvent('SUPPORT', { communication_method: 'chat' }) // ✅ 正常提示
trackEvent('NAVIGATION') // ❌ TS错误:缺少第二个参数
trackEvent('NAVIGATION', { screen: 'home' }) // ✅ 正常提示

原理说明

  • 利用剩余参数...args结合条件类型:Events[K] extends undefined ? [] : [eventValues: Events[K]]
  • 当事件K对应的Events[K]是undefined时,要求剩余参数为空数组,即无需传递第二个参数
  • 当Events[K]是其他类型时,要求剩余参数必须包含一个对应类型的元素,即第二个参数必填
  • 函数内部通过args[0]获取参数值,并用类型断言确保类型匹配

替代方案:函数重载

如果需要更直观的签名提示,可以用函数重载实现,但这种方式需要手动维护重载列表,新增值为undefined的事件时需要更新重载:

// 重载1:必填参数的事件
export function trackEvent<K extends Exclude<keyof Events, 'LOGIN'>>(eventName: K, eventValues: Events[K]): void;
// 重载2:可选参数的事件
export function trackEvent(eventName: 'LOGIN', eventValues?: undefined): void;
// 实现函数
export function trackEvent<K extends keyof Events>(eventName: K, eventValues?: Events[K]) {
  if (Platform.OS === 'web') return;
  logEvent(eventName, eventValues ?? {});
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 11:40:21