Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to document javascript higher order function?

I have the following higher order function for wrapping contructors:

/**
 * Wrapper for calling constructor with given parameters
 *
 * @param {Class} Cls
 * @returns {function} Wrapper on constructor which creates an instance of given Class
 */
function constructorWrapper(Cls) {
    return (...args) => new Cls(...args);
}

So if I have a class MyClass, I can do the following:

exports.MyClass = MyClass;
exports.myClass = constructorWrapper(MyClass);

Now the class can be instantiated in the following 2 ways after importing:

const instance1 = new MyClass(param1, param2);
const instance2 = myClass(param1, param2);

In vscode, instance1 will have intellisense support but instance2 won't. How do I document the function/export so that the objects created using the wrapper are recognised as instances of the class?

like image 951
Suhas K Avatar asked Oct 18 '22 14:10

Suhas K


1 Answers

You could make IntelliSense available by forcing the type of myClass:

/** @type {function(T1, T2): MyClass} */
exports.myClass = constructorWrapper(MyClass);

If you wish to annotate constructorWrapper itself, however, that's not possible as of VSCode 1.11.1 (with TypeScript 2.2). While JSDoc supports generics:

/**
 * Wrapper for calling constructor with given parameters
 *
 * @param {function(new:T, ...*)} Cls The class constructor.
 * @returns {function(...*): T} Wrapper of the class constructor
 * @template T
 */
function constructorWrapper(Cls) {
    return (...args) => new Cls(...args);
}

and the inferred type is indeed correct:

<code>function constructorWrapper<T>(Cls: new (...arg1: any[]) => T): (...arg0: any[]) => T</code>

Somehow the two "T" becomes disconnected, making myClass = constructorWrapper(MyClass) to adopt the type signature (...arg0: any[]) => T. What T? Well we don't know, treat it as any and no IntelliSense then.

<code>myClass: (...arg0: any[]) => T</code>

VSCode's JSDoc-based IntelliSense is based on TypeScript, and I think this is a bug in TypeScript's handling of @template as of 2.2.

If you are not constrained to ES6-only-development, I recommend you rewrite it entirely in TypeScript instead. Then you'll get the expected IntelliSense, plus type safety and many other benefits.

Note that since TypeScript 2.2 does not support variadic generics yet the arguments can't be perfectly forwarded, thus the input to the myClass cannot be type-checked. That means you still need to manually annotate the type of myClass to get perfect information.

like image 86
kennytm Avatar answered Oct 20 '22 22:10

kennytm