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

如何让TypeScript泛型自动适配listener类型实现参数补全?

问题描述

希望泛型T自动匹配listener字段的类型,无论listener是默认值还是自定义值,firstParameter都能获得自动补全,无需手动指定泛型类型。当前只能固定使用一种类型(dummy或upper),无法同时兼容多种,请问是否可行?如果不可行,除了将所有类型设为any外,还有其他解决办法吗?

代码示例

const upper = ({ helloWorld }: { helloWorld: string }) =>
    helloWorld.toUpperCase();

const dummy = ({ worldHello }: { worldHello: string }) => worldHello;

type objType<T extends (...args: any[]) => any = typeof upper> = {
    listener?: T;
    firstParameter: Parameters<T>[0];
};

const obj: objType = {
    listener: upper,
    firstParameter: {
        helloWorld: "hello world", // 自动补全正常
    },
};

// 期望实现的数组场景
let arr: objType[] = [
    obj,
    { listener: dummy, firstParameter: { worldHello: "world hello" } },
];

// 期望无需手动指定泛型就能获得自动补全
let dummyObj: objType = {
    listener: dummy,
    firstParameter: {
        // 这里想要自动补全,不用写 objType<typeof dummy>
    }
}
解决方案

核心结论

直接通过变量类型注解让泛型T根据listener属性反向推导是不可行的,因为TypeScript中变量的泛型类型必须显式指定或使用默认值,无法根据对象内部属性动态推导泛型参数。

替代方案1:用工厂函数创建对象(推荐)

利用函数的泛型推导特性,写一个工厂函数来生成目标对象,函数会自动根据传入的listener推导T的类型,无需手动指定:

const upper = ({ helloWorld }: { helloWorld: string }) =>
    helloWorld.toUpperCase();

const dummy = ({ worldHello }: { worldHello: string }) => worldHello;

type objType<T extends (...args: any[]) => any = typeof upper> = {
    listener?: T;
    firstParameter: Parameters<T>[0];
};

// 工厂函数,自动推导泛型T
const createObj = <T extends (...args: any[]) => any = typeof upper>(obj: objType<T>) => obj;

// 使用示例
const obj = createObj({
    listener: upper,
    firstParameter: { helloWorld: "hello world" }, // 自动补全
});

const dummyObj = createObj({
    listener: dummy,
    firstParameter: { worldHello: "world hello" }, // 自动补全
});

// 数组场景:使用联合类型数组
let arr: Array<objType<typeof upper> | objType<typeof dummy>> = [
    obj,
    dummyObj,
];

替代方案2:定义联合类型(适合固定数量的listener场景)

如果listener的类型是固定的几种,可以直接把objType定义为所有可能类型的联合类型,这样数组和单个对象都能获得正确的类型提示:

const upper = ({ helloWorld }: { helloWorld: string }) =>
    helloWorld.toUpperCase();

const dummy = ({ worldHello }: { worldHello: string }) => worldHello;

type objType<T extends (...args: any[]) => any = typeof upper> = {
    listener?: T;
    firstParameter: Parameters<T>[0];
};

type UpperObj = objType<typeof upper>;
type DummyObj = objType<typeof dummy>;
type AnyObj = UpperObj | DummyObj;

let arr: AnyObj[] = [
    { listener: upper, firstParameter: { helloWorld: "hello world" } },
    { listener: dummy, firstParameter: { worldHello: "world hello" } },
];

let dummyObj: AnyObj = {
    listener: dummy,
    firstParameter: { worldHello: "world hello" }, // 自动补全
};

方案对比

  • 工厂函数方案:扩展性强,新增listener类型无需修改类型定义,推荐用于动态场景。
  • 联合类型方案:类型提示更直接,但新增listener时需要手动更新联合类型,适合固定场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 10:45:46