可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is there a way to make the following work without having to define an implementation in the subclass which simply calls the superclass or unnecessarily repeats the non-specialized signature?
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 }
回答1:
Function overloads only get combined if they are call signatures on an object type. The easiest fix (for the interface case) is to separate out the function type into its own interface and extend that:
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
The equivalent version in the class case takes some work (assuming you care about the function going on the prototype -- if not, just use a function expression as an initializer for on instead):
class Emitter { on: EmitterEvent; } module Emitter { Emitter.prototype.on = function(name: string, handler: any) { // Code here } }
回答2:
Seems that with TS 1.5 the module trick (which is now called a namespace) won't work, as it complains about 'this'.
Below a working approach which I'm using:
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[]) {})