2015-02-24 84 views
4

有沒有一種方法可以在不需要簡單地調用超類或不必要地重複非專用簽名的子類中定義實現的情況下進行以下工作?在子類或接口上定義的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 
} 

回答

3

函數重載只有在對象類型是調用簽名時纔會合併。 (該接口的情況下),最簡單的解決方法是功能類型劃分爲不同的自己的接口和擴展:

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 
    } 
} 
+0

感謝瑞安!這種方法是可行的,但與在接口上聲明方法重載(ala addEventListener)非常不同。有沒有可能未來版本的TypesScript將允許類的方法重載來重用基類實現(假設它是兼容的)? – 2015-02-25 02:34:28

+1

不太可能,因爲這可能需要一些新的語法或重大更改。 – 2015-02-25 05:23:56

+0

函數在原型上運行的版本有一個缺點,函數不能調用同一類中的其他私有函數。 – 2017-04-27 11:37:37

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[]) {})