How does interfaces with construct signatures work? How does interfaces with construct signatures work? typescript typescript

How does interfaces with construct signatures work?


Construct signatures in interfaces are not implementable in classes; they're only for defining existing JS APIs that define a 'new'-able function. Here's an example involving interfaces new signatures that does work:

interface ComesFromString {    name: string;}interface StringConstructable {    new(n: string): ComesFromString;}class MadeFromString implements ComesFromString {    constructor (public name: string) {        console.log('ctor invoked');    }}function makeObj(n: StringConstructable) {    return new n('hello!');}console.log(makeObj(MadeFromString).name);

This creates an actual constraint for what you can invoke makeObj with:

class Other implements ComesFromString {    constructor (public name: string, count: number) {    }}makeObj(Other); // Error! Other's constructor doesn't match StringConstructable


On my search for the exact same question I went looking how the TypeScript-Team did that...

They are declaring an interface and afterwards a variable with a name matching exactly the interface-name. This is also the way to type static functions.

Example from lib.d.ts:

interface Object {    toString(): string;    toLocaleString(): string;    // ... rest ...}declare var Object: {    new (value?: any): Object;    (): any;    (value: any): any;    // ... rest ...}

I tried that and it works like charm.


Well an interface with a construct signature is not meant to be implemented by any class(at first glance this might look weird for guys with C#/Java background like me but give it a chance). It is slightly different.

For a moment think of it as a interface with a call signature(like a @FunctionalInterface in Java world). Its purpose is to describe a function type..kind of. The described signature is supposed to be satisfied by a function object...but not just any high level function or a method. It should be a function which knows how to construct an object, a function that gets called when new keyword is used.

So an interface with a construct signature defines the signature of a constructor ! The constructor of your class that should comply with the signature defined in the interface(think of it as the constructor implements the interface). It is like a factory !

Here is a short snippet of code that tries to demonstrate the most common usage:

interface ClassicInterface { // old school interface like in C#/Java    method1();    ...    methodN();}interface Factory { //knows how to construct an object    // NOTE: pay attention to the return type    new (myNumberParam: number, myStringParam: string): ClassicInterface}class MyImplementation implements ClassicInterface {    // The constructor looks like the signature described in Factory    constructor(num: number, s: string) { } // obviously returns an instance of ClassicInterface    method1() {}    ...    methodN() {}}class MyOtherImplementation implements ClassicInterface {    // The constructor looks like the signature described in Factory    constructor(n: number, s: string) { } // obviously returns an instance of ClassicInterface    method1() {}    ...    methodN() {}}// And here is the polymorphism of constructionfunction instantiateClassicInterface(ctor: Factory, myNumberParam: number, myStringParam: string): ClassicInterface {    return new ctor(myNumberParam, myStringParam);}// And this is how we do itlet iWantTheFirstImpl = instantiateClassicInterface(MyImplementation, 3.14, "smile");let iWantTheSecondImpl = instantiateClassicInterface(MyOtherImplementation, 42, "vafli");