TypeScript Version:
1.8.10
Code
Taken from http://www.typescriptlang.org/docs/handbook/interfaces.html
Just changed the return to omit errors by implicit any.
interface ClockConstructor {
new (hour: number, minute: number): ClockConstructor;
}
class Clock implements ClockConstructor {
currentTime: Date;
constructor(h: number, m: number) { }
}
Expected behavior:
Clock correctly implements ClockConstructor
Actual behavior:
Error:(5, 7) TS2420: Class 'Clock' incorrectly implements interface 'ClockConstructor'.
Type 'Clock' provides no match for the signature 'new (hour: number, minute: number): ClockConstructor'
That example is meant to illustrate an error, as is mentioned in the surrounding handbook text. The error is actually what is expected.
Okay, so to summarize. There is no possibility to create a full Interface for a class with a constructor?
Yes, there is, but it ends up being _two_ interfaces, one for the static side and one for the instance side:
interface ClockConstructor {
new (hour: number, minute: number): ClockInstance;
}
interface ClockInstance {
currentTime: Date;
}
class Clock implements ClockInstance {
currentTime: Date;
constructor(h: number, m: number) { }
}
var cc: ClockConstructor = Clock;
var ci = new cc(9, 15);
var t = ci.currentTime;
I guess it couldn't be made more complicated.
It is only logical. A JavaScript class
is essentially a constructor function with a prototype. There is the interface to the constructor function, along with any "static" methods and properties, and then there is the interface to the prototype, which the constructor function creates a new instance of when the function is called with the new
keyword.
TypeScript typically abstracts you from that complexity when you use the class
keyword. But the complexity is trying to describe things in the underlying language (ECMAScript), not some arbitrary complexity in TypeScript.
Some would question that creating a whole interface for a class couldn't be more complicated. What is the use case for creating it, when even in definition files, classes can be described as a single interface using the class
keyword?
Well, the most ugly point about this is, that I have to create an empty interface for the empty static part of my class. And my IDE also tells me, that the Constructor Interface is not used. What sounds only logic to me, because there is no implementation reference for the constructor interface.
Well, the most ugly point about this is, that I have to create an empty interface for the empty static part of my class.
Again, why are you creating interfaces for constructors? I think you are mis-understanding something. You asked how to do it (which was explained) but you have articulated what your use case is for doing it. As mentioned, above, in definition files (.d.ts
) class
is a special keyword that automatically expresses both those interfaces and do not require an implementation.
I'm creating the interface for a constructor, so I can pass the class reference in an configuration object. The configuration can point to different classes that all extend the same abstract class which implements the interface. To make compile work with this I need an interface for the constructor to use the interface instead of the abstract class as the type reference.
When used as a type, the keyword typeof
refers to the interface of the constructor instead of the instances created. For example:
class Foo {
foo: string = 'foo';
}
function onlyFooConstructor(Ctor: typeof Foo) {
console.log(Ctor);
}
onlyFooConstructor(Foo);
const foo = new Foo();
onlyFooConstructor(foo); // Errors
class Bar extends Foo {
bar: string = 'bar';
}
onlyFooConstructor(Bar);
class Baz {
baz: string = 'baz';
}
onlyFooConstructor(Baz); // Errors
But remember, TypeScript is a structural typing language, versus nominal, so if the constructor is the same shape (e.g. has matching static methods and generates an object that is assignable to the prototype of the constructor) it will pass the guard.
Most helpful comment
I guess it couldn't be made more complicated.