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

如何根据函数参数值提取联合类型属性?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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:52:21