Search code examples
typescriptinvoke

Typescript: how to define an invokable object?


This comes from @types/d3:

export interface ScaleContinuousNumeric<Range, Output> {
    (value: number | { valueOf(): number }): Output;

but that's an interface. How do I define a class, the instances of which can be invoked like functions? Something like this:

const inverter = new Inverter();
const question = inverter(42);

Maybe there is some kind of special ES6 Symbol like

class Inverter {
    [Symbol.invokable]() {

    }
}

or TypeScript syntax?


Solution

  • You just define a regular function, that will satisfy the interface with the call signature:

    export interface ScaleContinuousNumeric<Range, Output> {
        (value: number | { valueOf(): number }): Output;
    }
    
    let a : ScaleContinuousNumeric<number, string> = (value) => value.toString()
    

    If the interface has other methods you can use Object.assign to create the function and add the properties:

    export interface ScaleContinuousNumeric<Range, Output> {
        (value: number | { valueOf(): number }): Output;
        otherValue: Range
    }
    
    let a: ScaleContinuousNumeric<number, string> = Object.assign(
        (value: number | { valueOf(): number }) => value.toString(), {
            otherValue: 1
        });
    

    Or in typescript 3.0 you can create the function, assign the extra properties and then the function will be compatible with the interface:

    export interface ScaleContinuousNumeric<Range, Output> {
        (value: number | { valueOf(): number }): Output;
        otherValue: Range
    }
    
    function myFunc(value: number | { valueOf(): number }) {
        return value.toString()
    }
    myFunc.otherValue = 1
    let a: ScaleContinuousNumeric<number, string> = myFunc