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

如何实现TypeScript泛型函数的参数类型关联与指定返回类型

问题描述

我需要给函数指定泛型类型,使其返回泛型中定义的指定类型,同时第二个参数需从对应channel的events中做类型查找。期望调用listen<MenuChannels>('menu','1')时,返回类型为'3'。

当前函数定义存在参数类型与返回类型无法正常关联的问题:

listen<T extends WebsocketChannel[]>(
    name: T[number]['channel'],
    event: T[number]['events'][number]['name'], // 无法关联到对应channel的events
  ): Observable<any> { // 返回类型无法对应到event的value
}

相关类型定义:

export interface WebsocketChannel {
  channel: string
  events: Event[]
}

interface Event {
  name: string
  value: any
}

export type MenuChannels = [
  {
    channel: 'menu'
    events: Menu1Events
  },
  {
    channel: 'menu-2'
    events: Menu2Events
  },
]

export type Menu1Events = [
  {
    name: '1'
    value: '3'
  },
  {
    name: '2'
    value: '4'
  },
]

export type Menu2Events = [
  {
    name: '5'
    value: '7'
  },
  {
    name: '6'
    value: '8'
  },
]
解决方案

要实现参数与返回值的类型关联,需通过双重泛型绑定+条件类型提取来实现精准的类型约束:

import { Observable } from 'rxjs';

export interface WebsocketChannel {
  channel: string;
  events: { name: string; value: any }[];
}

// 工具类型:从Channels数组中提取对应channel名称的通道类型
type ChannelFromChannels<Channels extends WebsocketChannel[], ChannelName extends string> = 
  Extract<Channels[number], { channel: ChannelName }>;

// 工具类型:从指定通道的events中提取对应event名称的value类型
type EventValueFromChannel<Channel extends WebsocketChannel, EventName extends string> = 
  Extract<Channel['events'][number], { name: EventName }>['value'];

// 修改后的listen函数
function listen<
  Channels extends WebsocketChannel[],
  ChannelName extends Channels[number]['channel'],
  EventName extends ChannelFromChannels<Channels, ChannelName>['events'][number]['name']
>(
  name: ChannelName,
  event: EventName
): Observable<EventValueFromChannel<ChannelFromChannels<Channels, ChannelName>, EventName>> {
  // 函数原有逻辑保持不变
  return new Observable();
}

// 测试用例(保留原类型定义)
export type MenuChannels = [
  { channel: 'menu'; events: Menu1Events },
  { channel: 'menu-2'; events: Menu2Events },
];

export type Menu1Events = [
  { name: '1'; value: '3' },
  { name: '2'; value: '4' },
];

export type Menu2Events = [
  { name: '5'; value: '7' },
  { name: '6'; value: '8' },
];

// 调用示例:返回类型自动推断为Observable<'3'>
const result = listen<MenuChannels>('menu', '1');

关键改动说明

  1. 新增工具类型
    • ChannelFromChannels:从传入的Channels数组中,精准提取与当前channel名称匹配的通道类型
    • EventValueFromChannel:从指定通道的events列表中,提取与当前event名称匹配的value类型
  2. 泛型约束升级
    • 新增ChannelName泛型,绑定传入的channel名称,确保只能使用Channels数组中存在的channel值
    • 新增EventName泛型,约束为当前选中channel的events列表中的name值,实现参数之间的联动校验
  3. 返回类型精准化
    • 通过工具类型组合,直接返回对应event的value类型,替代原有的any,实现类型的自动推断

修改后,调用listen<MenuChannels>('menu','1')时,TypeScript会自动推断返回类型为Observable<'3'>,同时参数会有严格的类型提示:输入不存在的channel或event名称时,编辑器会直接抛出类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:22:49