我已经扩展了EventEmitter类并使用了函数重载,以便在使用特定字符串调用addListener时,回调将自动键入:

const codes = {
    code1: 'code1',
    code2: 'code2',
} as const;

type CodeType = typeof codes;

interface Code1Interface { a: string };
interface Code2Interface { b: boolean };

class MyEmitter { // extends ...
    public addListener(code: CodeType['code1'], callback: (event: Code1Interface) => void): void;
    public addListener(code: CodeType['code2'], callback: (event: Code2Interface) => void): void;
    public addListener(code: CodeType[keyof CodeType], callback: (event: any) => void): void; // fallback
    public addListener(code: any, callback: any) {
        // call the parent addListener here
    }
}

但是,我有一个函数可以将addListener封装到Promise中,而TypeScrip无法猜测返回类型:

function getEvent(code: CodeType[keyof CodeType]) { // returns Promise<unknown>
    return new Promise((resolve, reject) => {
        const emitter = new MyEmitter();
        emitter.addListener(code, (event) => resolve(event));
    })
}

getEvent(codes.code1).then(x => x) // x has type unknown

是否可以将函数重载中定义的接口类型转发给getEvent函数的调用方,或者执行可以在MyEmitter类中重用的更一般的映射?

demo

推荐答案

Overloads目前不能很好地泛化;当您直接调用它们时,它们只能解析为"正确的"调用签名.如果您try 使用高阶行为,如类型推断,编译器往往会放弃,只 Select 最后一个调用签名.这种情况有时可能会改变(在microsoft/TypeScript#52944有一个拉请求,如果合并会改善情况),但从TypeScrip5.1开始,重载很难操作.

对于您的示例代码,我倾向于从重载切换到generics:

type CodeValMap = {
    code1: Code1Interface;
    code2: Code2Interface;
    [k: string]: any;
}

class MyEmitter { 
    
    public addListener<K extends keyof CodeValMap>(
      code: K, callback: (event: CodeValMap[K]) => void
    ): void;

    public addListener(code: any, callback: any) {}
}

function getEvent<K extends keyof CodeValMap>(code: K) {
    return new Promise<CodeValMap[K]>((resolve, reject) => {
        const emitter = new MyEmitter();
        emitter.addListener(code, (event) => resolve(event));
    })
}

在这里,我们将CodeValMap定义为从字符串literal types"code1""code2"到相应的event类型的映射(如果需要,可以添加指向anyindex signature以获得回退行为).

MyEmitter‘S addListenerK extends keyof CodeValMap中是泛型的,因此它接受两个相关的codecallback参数.那么getEvent()基本上是以与K extends keyof CodeValMap中的泛型函数相同的方式编写的,我们返回Promise<CodeValMap[K]>,以便code的类型传递到返回类型:

getEvent(codes.c1).then(x => x) // (parameter) x: Code1Interface
getEvent(codes.c2).then(y => y) // (parameter) y: Code2Interface
getEvent("hoobydooby").then(z => z) // (parameter) z: any

看上go 不错!

Playground link to code

Typescript相关问答推荐

React组件数组及其props 的类型定义

如何从具有给定键列表的对象类型的联合中构造类型

TypeScript实用程序类型—至少需要一个属性的接口,某些指定属性除外

Angular中的其他服务仅获取默认值

在TypeScript中,除了映射类型之外还使用的`in`二进制运算符?

如果一个变量不是never类型,我如何创建编译器错误?

更新为Angular 17后的可选链运算符&?&问题

如何在TypeScript中将一个元组映射(转换)到另一个元组?

如何将泛型对象作为返回类型添加到类型脚本中

有没有可能为这样的函数写一个类型?

TypeScrip:来自先前参数的参数中的计算(computed)属性名称

使用TypeScrip的类型继承

Angular material 无法显示通过API获取的数据

类型';字符串|数字';不可分配给类型';未定义';.类型';字符串';不可分配给类型';未定义';

在类型脚本中将泛型字符串数组转换为字符串字母并集

作为函数参数的联合类型的键

如何调整项目数组,但允许权重影响顺序

导航链接不触发自定义挂钩

我可以在 Typescript 中重用函数声明吗?

如何使用 TypeScript 接口中第一个属性的值定义第二个属性