如何实现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');
关键改动说明
- 新增工具类型
ChannelFromChannels:从传入的Channels数组中,精准提取与当前channel名称匹配的通道类型EventValueFromChannel:从指定通道的events列表中,提取与当前event名称匹配的value类型
- 泛型约束升级
- 新增
ChannelName泛型,绑定传入的channel名称,确保只能使用Channels数组中存在的channel值 - 新增
EventName泛型,约束为当前选中channel的events列表中的name值,实现参数之间的联动校验
- 新增
- 返回类型精准化
- 通过工具类型组合,直接返回对应event的value类型,替代原有的
any,实现类型的自动推断
- 通过工具类型组合,直接返回对应event的value类型,替代原有的
修改后,调用listen<MenuChannels>('menu','1')时,TypeScript会自动推断返回类型为Observable<'3'>,同时参数会有严格的类型提示:输入不存在的channel或event名称时,编辑器会直接抛出类型错误。
内容的提问来源于stack exchange,提问作者MikeLwo
相关产品推荐
相关产品推荐

