I've been playing a bit with interfaces with construct signatures in TypeScript, and I became a bit confused when the following failed to type check:
class Foo {
constructor () {
}
}
interface Bar {
new(): Bar;
}
function Baz(C : Bar) {
return new C()
}
var o = Baz(Foo);
The type error is:
Supplied parameters do not match any signature of call target: Construct signatures of types 'new() => Foo' and 'Bar' are incompatible: Type 'Bar' requires a construct signature, but Type 'Foo' lacks one (C: Bar) => Bar
The type of Foo's constructor is () => Foo, and that is what I thought that Bar said. Am I missing something here?
Benefits to using TypeScript interface constructors With a constructor on the interface, you can specify that all of your types must have certain methods/properties (normal interface compliance) but also control how the types get constructed by typing the interface like you would with any other method/property.
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!
// One major difference between type aliases vs interfaces are that interfaces are open and type aliases are closed. This means you can extend an interface by declaring it a second time. // In the other case a type cannot be changed outside of its declaration.
An interface type cannot be passed as a parameter. When running TypeScript code, you are really compiling it down to JavaScript and then running the JavaScript. An interface is a TypeScript compile-time construct, so at runtime, there is no such thing as an interface type to call functions on or inspect properties of.
Here is an updated version of your code with a subtle change.
We define the Bar
interface with whatever functions and variables we expect to be present.
Next, we extend the Bar
interface with the NewableBar
interface. This just defined a constructor that returns a Bar
.
Because Foo
implements Bar
and has a constructor and Baz
requires a NewableBar
, everything is checked.
This is a little more verbose than any
- but gives you the checking you want.
interface Bar {
}
interface NewableBar extends Bar {
new();
}
class Foo implements Bar {
constructor () {
}
}
function Baz(C : NewableBar) {
return new C()
}
var o = Baz(Foo);
The problem (at least from the TypeScript compiler's point of view) is the signature of Bar
's new
method. If you replace the definition of Bar
with the following,
interface Bar {
new (): any;
}
it works. You might as well use new (): Foo
, just Bar
as return value does not work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With