6

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?

1
  • 1
    Javascript sometimes not really good documented on vscode, use Typescript instead :( Commented Apr 13, 2017 at 4:11

1 Answer 1

4
+50

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for taking the time to answer this. However, manually annotating the type of myClass did not work in vscode. However, I suspect that this is a bug/missing feature and there is no better solution. I am upvoting the answer anyway.
@SuhasK Manually adding the @type works for me on VSCode 1.11.1 with TypeScript 2.2.2. Maybe a problem in your import statement?
Indeed it works if the class definition is present in the same file where it is being exported. If it is being imported and then exported(as is my case), intellisense does not work even with the manual type annotation. ibb.co/m5qW0k
@SuhasK Maybe try (a) use the syntax import * as exp from './base'? (b) Restart VSCode? I don't have other ideas if these still don't work :).
No.. That did not help. But I'll keep the manual type annotations with the hope that they'll work in the future.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.