在子类或接口上定义的Typescript专用重载

时间:2015-02-24 18:33:49

标签: typescript

有没有办法进行以下工作而不必在子类中定义一个只调用超类或不必要地重复非专用签名的实现?

class Emitter {
    on(name: 'one', handler: (value: number) => void): void;
    on(name: string, handler: (...args: any[]) => void): void;
    on(name: string, handler: (...args: any[]) => void): void { 
        // do stuff
    }
}


class Subclass extends Emitter {
    on(name: 'two', handler: (value: string) => void): void;
    on(name: string, handler: (...args: any[]) => void): void;
    // error no implementation specified
}


interface IEmitter {
    on(name: 'one', handler: (value: number) => void): void;
    on(name: string, handler: (...args: any[]) => void): void;
}


interface ISubclass extends IEmitter {
    on(name: 'two', handler: (value: string) => void): void;
    // error overload not assignable to non specialized
}

2 个答案:

答案 0 :(得分:2)

如果函数重载是对象类型的调用签名,则它们才会合并。最简单的修复(对于接口情况)是将函数类型分离到它自己的接口并扩展它:

interface EmitterEvent {
    (name: 'one', handler: (value: number) => void): void;
    (name: string, handler: (...args: any[]) => void): void;
}

interface SubclassEmitterEvent extends EmitterEvent {
    (name: 'two', handler: (value: string) => void): void;
}

interface IEmitter {
    on: EmitterEvent;
}

interface ISubclass extends IEmitter {
    on: SubclassEmitterEvent;
}

var x: ISubclass;
x.on('one', n => n.toFixed()); // n: number
x.on('two', s => s.substr(0)); // s: string
var y: IEmitter;
y.on('two', a => a); // a: any

类案例中的等效版本需要一些工作(假设您关心原型上的函数 - 如果没有,只需使用函数表达式作为on的初始化器):

class Emitter {
    on: EmitterEvent;
}
module Emitter {
    Emitter.prototype.on = function(name: string, handler: any) {
        // Code here
    }
}

答案 1 :(得分:0)

似乎在TS 1.5中,模块技巧(现在称为命名空间)不起作用,因为它抱怨“这个”。

以下是我正在使用的工作方法:

interface EventEmitterOn {
    (event: string, listener: () => void);
}

interface FooEventEmitterOn extends EventEmitterOn {
    (event: 'dependency', listener: (dep: string[]) => void);
}

class EventEmitter {
    on: EventEmitterOn;
}

EventEmitter.prototype.on = function(event, listener) {
    // implementation
}

class Foo extends EventEmitter {
    on: FooEventEmitterOn;
}

var foo = new Foo
// error
foo.on('dependency', function(dep: number) {})
// ok
foo.on('dependency', function(dep: string[]) {})