Typescript specialized overloads defined on a subclass or interface

匿名 (未验证) 提交于 2019-12-03 08:48:34

问题:

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


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!