Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript specialized overloads defined on a subclass or interface

Tags:

typescript

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
}
like image 463
Chris Colbert Avatar asked Nov 01 '22 09:11

Chris Colbert


1 Answers

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
    }
}
like image 200
Ryan Cavanaugh Avatar answered Nov 12 '22 19:11

Ryan Cavanaugh