如何根据函数参数值提取联合类型属性?TypeScript类型推导问询
如何让TypeScript根据eventType自动推导回调函数类型
核心问题本质
要让编译器把eventType的具体值和回调的参数类型绑定,本质是要建立两个参数之间的类型依赖关系,这不能直接通过运行时值实现,必须借助TypeScript的类型系统特性。
你的两种写法问题分析
- 直接用
eventType作为类型:TS中值(变量)和类型是完全独立的命名空间,不能直接把值当作类型使用,所以报错是必然的。 - 使用
typeof eventType:eventType的类型是APIType(联合类型),所以typeof eventType等价于APIType,Extract<UnionAPI, {type: typeof eventType}>会匹配UnionAPI的所有成员,最终Data类型变成联合类型,不符合你想要的“对应单一类型”的需求。
更简便的泛型优化方案
你现有的泛型方案可以优化,不需要手动指定泛型参数,让TypeScript自动从eventType推导T的类型:
const enum APIType { API1 = 1, API2 = 2 } interface API1{ type: APIType.API1, Data: number[] } interface API2{ type: APIType.API2, Data: { isAdmin: boolean, data: number[] } } type UnionAPI = API1 | API2; // 优化后的泛型写法:让TS自动推导T const useListenAPI = <T extends APIType>( eventType: T, callback: (data: Extract<UnionAPI, {type: T}>["Data"]) => void ) => { // do whatever } // 调用时无需手动指定泛型,TS自动推导 useListenAPI(APIType.API1, (data) => { // data 自动推导为 number[] console.log(data.length); }); useListenAPI(APIType.API2, (data) => { // data 自动推导为 {isAdmin: boolean, data: number[]} console.log(data.isAdmin); });
这个方案的关键是把T约束为APIType的子类型,然后让TS通过传入的eventType具体值自动推断T,进而确定Extract后的Data类型,完全不需要手动指定泛型参数,已经很简便了。
另一种方案:函数重载
如果你觉得泛型不够直观,也可以用函数重载来实现,为每个APIType成员定义单独的函数签名:
const enum APIType { API1 = 1, API2 = 2 } type API1Data = number[]; type API2Data = {isAdmin: boolean, data: number[]}; // 重载签名 function useListenAPI(eventType: APIType.API1, callback: (data: API1Data) => void): void; function useListenAPI(eventType: APIType.API2, callback: (data: API2Data) => void): void; // 实现签名(注意:实现签名的参数类型要兼容所有重载签名) function useListenAPI(eventType: APIType, callback: (data: API1Data | API2Data) => void) { // do whatever } // 调用时自动推导 useListenAPI(APIType.API1, (data) => { // data: API1Data }); useListenAPI(APIType.API2, (data) => { // data: API2Data });
这种方案的优点是直观,每个API类型对应明确的签名;缺点是如果APIType成员较多,需要写大量重载签名,扩展性不如泛型。
结论
这并没有超出TypeScript的能力范围,但必须借助类型系统的特性(泛型或重载)来实现参数间的类型关联。其中优化后的泛型方案是最简便且可扩展的,不需要手动指定泛型参数,编译器会自动完成推导。
内容的提问来源于stack exchange,提问作者etblh
相关产品推荐
相关产品推荐

