Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a Typescript class implement a callable interface?

Typescript interfaces allow definition of a function-style call signature thus:

interface A {
    (x: number): number;
}

This can be implemented by, e.g. a function:

const a: A = function(x: number): number {
    return 1;
}

Is it possible to implement such an interface using a class?

I've attempted it like this:

class B implements A {
    (x: number): number {
        return 1;
    }
}

But I get this error:

Class 'B' incorrectly implements interface 'A'. Type 'B' provides no match for the signature '(x: number): number'.ts(2420)

Is there any way to implement this sort of interface using a class in Typescript?

like image 321
Josh Hansen Avatar asked Sep 18 '26 23:09

Josh Hansen


1 Answers

This is possible. In my projects I implemented a Callable helper class merged with an interface with the same name. The merge with the interface is needed to give TypeScript the correct function signature typings:

export interface Callable<T extends unknown[] = unknown[], R = unknown> {
    (...args: T): R;
}

export class Callable<T extends unknown[] = unknown[], R = unknown> extends Function {
    public constructor(func: (...args: T) => R) {
        super();
        return Object.setPrototypeOf(func, new.target.prototype) as typeof this;
    }
}

Using this class is pretty straight forward:

class Test extends Callable<[ number, number ], number> {
    public multiplier = 2;

    public constructor() {
        super((a, b) => (a + b) * this.multiplier);
    }
}

const test = new Test();
console.log(test(1, 2)); // Prints 6
test.multiplier = 3;
console.log(test(1, 2)); // Prints 9

Some explanations:

  • You define the function argument types in the first type parameter in form of an array. [ number, number] in this case means the function expects two numeric parameters.
  • You define the return type of the function as second type parameter. In this case this is again number.
  • You pass the actual function which is called when calling the class instance as a function to the constructor of the Callable super class.

Warning! Only use this if you like the functionality and don't care much about performance. Because a callable class instance is a lot slower than a real function! (Node.js and Chrome: 20 times slower, Firefox: 5 times slower).

like image 56
kayahr Avatar answered Sep 20 '26 13:09

kayahr