How to make a class implement a call signature in Typescript?
The code examples in this answer assume the following declaration:
var implementation: MyInterface;
Providing an implementation of a callable interface
As a follow-up to the accepted answer, as suggested by some of its commentors, a function that matches the interface's call signature implicitly implements the interface. So you can use any matching function as an implementation.
For example:
implementation = () => "Hello";
You don't need to explicitly specify that the function implements the interface. However, if you want to be explicit, you can use a cast:
implementation = <MyInterface>() => "Hello";
Providing a reusable implementation
If you want to produce a reusable implementation of the interface like you normally would with a Java or C# interface, just store the function somewhere accessible to its consumers.
For example:
function Greet() {
return "Hello";
}
implementation = Greet;
Providing a parameterised implementation
You may want to be able to parameterise the implementation in the same way that you might parameterise a class. Here's one way to do this:
function MakeGreeter(greeting: string) {
return () => greeting;
}
implementation = MakeGreeter("Hello");
If you want the result to be typed as the interface, just explicitly set the return type or cast the value being returned.
Classes can't match that interface. The closest you can get, I think is this class, which will generate code that functionally matches the interface (but not according to the compiler).
class MyType implements MyInterface {
constructor {
return "Hello";
}
}
alert(MyType());
This will generate working code, but the compiler will complain that MyType
is not callable because it has the signature new() = 'string'
(even though if you call it with new
, it will return an object).
To create something that actally matches the interface without the compiler complaining, you'll have to do something like this:
var MyType = (() : MyInterface => {
return function() {
return "Hello";
}
})();
alert(MyType());
In case if callable interface should have other methods you can do it like this:
interface Greeter {
(): void;
setName(name: string): void;
}
class ConsoleGreeter {
private constructor( // constructable via `create()`
private name = 'world'
) {}
public call(): void {
console.log(`Hello ${this.name}!`);
}
public setName(name: string) {
this.name = name;
}
public static create(): Greeter {
const instance = new ConsoleGreeter();
return Object.assign(
() => instance.call(),
{
setName: (name: string) => instance.setName(name)
// ... forward other methods
}
);
}
}
const greeter = ConsoleGreeter.create();
greeter(); // prints 'Hello world!'
greeter.setName('Dolly');
greeter(); // prints 'Hello Dolly!'
Downside: greeter instanceof ConsoleGreeter
is false