27

i have a "compilation" problem in this case :

interface IDataObjectConstructor {
    new (objJSON?: any): myDataObject;
}

class myDataObject implements IDataObjectConstructor {
    constructor(objJSON: any = null) {
        for (var prop in objJSON) {
            this[prop] = objJSON[prop];
        }
    }
}

it say :

class 'myDataObject' incorrectly implements interface 'IDataObjectConstructor'.

Type 'myDataObject' provides no match for signature 'new (objJSON?: any) : myDataObject'

Finally i want to use this object like this :

class viewModelList<T extends myDataObject>{
    item: T;
    constructor(itemType: T) { this.item = itemType; }

    itemBuilder(json?) { return new this.item(json); }
}

class derivedDataObject extends myDataObject{
    constructor(objJSON: any = null) { super(objJSON); }
}

class derivedViewModelList extends viewModelList<derivedDataObject>{

    constructor() { super(derivedDataObject); }
}

let oManager = new derivedViewModelList();
Community
  • 1
  • 1
Clemsouz
  • 291
  • 1
  • 3
  • 5
  • 1
    See [this](http://stackoverflow.com/a/13408029/1263942). TD;LR;: Construct signatures in interfaces are not implementable in classes – Bruno Grieder Jun 06 '16 at 13:49
  • Possible duplicate of [How does typescript interfaces with construct signatures work?](http://stackoverflow.com/questions/13407036/how-does-typescript-interfaces-with-construct-signatures-work) – Bruno Grieder Jun 06 '16 at 13:50

2 Answers2

30

Difference between the static and instance sides of classes

When working with classes and interfaces, it helps to keep in mind that a class has two types: the type of the static side and the type of the instance side. You may notice that if you create an interface with a construct signature and try to create a class that implements this interface you get an error:

interface ClockConstructor {
    new (hour: number, minute: number);
}

class Clock implements ClockConstructor { // error
    constructor(h: number, m: number) { } 
}

This is because when a class implements an interface, only the instance side of the class is checked. Since the constructor sits in the static side, it is not included in this check.

Instead, you would need to work with the static side of the class directly. In this example, we define two interfaces, ClockConstructor for the constructor and ClockInterface for the instance methods. Then for convenience we define a constructor function createClock that creates instances of the type that is passed to it.

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}
class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

Because createClock’s first parameter is of type ClockConstructor, in createClock(AnalogClock, 7, 32), it checks that AnalogClock has the correct constructor signature.

See the documentation for more.

activedecay
  • 10,129
  • 5
  • 47
  • 71
4

You don't need your class to implement the constructor interface, that happens automatically.

For example:

interface IDataObjectConstructor {
    new (objJSON?: any): myDataObject;
}

class myDataObject {
    constructor(objJSON: any = null) {
        for (var prop in objJSON) {
            this[prop] = objJSON[prop];
        }
    }
}

function factory(ctor: IDataObjectConstructor) {
    return new ctor();
}

let o = factory(myDataObject);

(code in playground)

The factory function expects an IDataObjectConstructor and we're passing the class itself and you don't get any compilation errors even though your class isn't declared to implement it.

Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • Thanks for helping, but i need to implement because i use this class in another like this : class viewModelListe{ item: T; itemBuilder(json?) { return this.item(json); } } – Clemsouz Jun 06 '16 at 12:21
  • I'm not sure what you mean. Please edit your question and add the code for this other case – Nitzan Tomer Jun 06 '16 at 13:03
  • 1
    @Clemsouz your snippet there doesn't use the interface, it simply says the type `T` extends `dataObject`.. so the above example should work there. having said that, this answer improperly addresses the issue you're seeing in compilation and the concept of automatic implementation of a constructor interface is incorrect.. if the constructor was changed to `objJSON?: string` neither `factory(myDataObject)` nor `return new ctor()` would present an issue with a bad constructor signature on `myDataObject`.. – Brett Caswell Nov 19 '16 at 16:46
  • additionally, if you were to change `factor` method to return `new ctor({ name : ""})` and `IDataObjectConstructor` to have a more specific signature (like any other type then `any`), you would see a warning on `new ctor({ name :""});` (not `factory(myDataObject)` mind you) but it would compile and construct an instance of myDataObject properly.. – Brett Caswell Nov 19 '16 at 16:52
  • still, this is the expected implementation pattern for this.. `IDataObjectConstructor` is not an interface for implementation. review `angular.IServiceProvider` and `angular.IServiceProviderClass` with the consideration of that pattern @NitzanTomer provided in his answer. – Brett Caswell Nov 19 '16 at 17:14