Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: How to define a class that produces callable instances

Tags:

typescript

I am currently converting a JS class to TypeScript. The class extends from the NPM module node-callable-instance (which makes it a subclass of Function internally). Instances of the class can be called like functions. Short example:

import * as CallableInstance from "callable-instance";

class MyClass extends CallableInstance {
  constructor() { super('method'); }
  method(msg) { console.log(msg); }
}

const inst = new MyClass();
inst('test'); // call will be forwarded to "method()"

It is a requirement of that special project that these instances are callable, other build-time tooling depends on that.

Is there a way to express that in TypeScript? The code above gives

error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'MyClass' has no compatible call signatures.

My first try to workaround this by using a callable interface failed as the class does not implement the call signature...

import * as CallableInstance from "callable-instance";

interface MyClassCallable {
  (msg: string): void;
}

class MyClass extends CallableInstance implements MyClassCallable {
  constructor() { super('method'); }
  method(msg: string): void { console.log(msg); }
}

const inst = new MyClass();
inst('test'); // call will be forwarded to "method()"
like image 724
Daniel R Avatar asked Jul 31 '18 06:07

Daniel R


1 Answers

The simplest solution is to use interface-class merging and declare an interface with the same name that has the callable signature. The resulting type will have members defined by both the interface and the class:

import * as CallableInstance from "callable-instance";

class MyClass extends CallableInstance {
    constructor() { super('method'); }
    method(msg: string): void { console.log(msg); }
}

interface MyClass {
    (name: string): void
}

const inst = new MyClass();
inst('test'); // call will be forwarded to "method()"
like image 185
Titian Cernicova-Dragomir Avatar answered Sep 28 '22 07:09

Titian Cernicova-Dragomir