Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write JSdoc for generic function in typescript

I've distilled an essence of my problem with following codes:

full source

I have Base class, and Derived, Derived2:

class Base {
    static get type() {
        return 'Base';
    }
}

class Derived extends Base {
}

class Derived2 extends Base {
}

Now I have variable t, which could be an instance of Derived or Derived2. It can also be changed multiple times during runtime.

/** @type {Base} */
var t = new Derived();
//or
var t = new Derived2();

And I have a function which checks whether t is an instance of passed-class, and returns t if it's an instance of the passed class or undefined otherwise.

/**
 * @template {typeof Base} T
 * @param {T} cl
 * @returns {T}  /// <-- I can't figure out how to return an instance of T
 * @returns {instanceof T} /// it's hypothetical, but I need this..
 */
function checkTop( cl ) {
    if ( t instanceof cl ) {
        return t;
    }
    return undefined;
}

When I call checkTop( Derived ), its return type should be Derived. But with above jsdoc, its return type is 'typeof Derived'. But I want to make the return type just 'Derived'.

let d1 = checkTop( Derived ); // 'typeof Derived', but I want 'Derived' as return type

d1 is recognized as 'typeof Derived'

likewise, d2 is recognized as 'typeof Derived2'

let d2 = checkTop( Derived2 ); // 'typeof Derived2'.. but I want 'Derived2' as return type

d2 is recognized as 'typeof Derived2'

How can I specify the return type in JSDOC so that checkTop( Derived ); has return type as Derived, and checkTop( Derived2 )'s return type is 'Derived2'.

I tried following for the return type:

/**
 * @template {Base} B 
 * @template {typeof B} T
 * @param {T} cl
 * @returns {B}
 */
function checkTop( cl )

and

/**
 * @template {typeof Base} T
 * @param {T} cl
 * @returns {instanceof T}
 */
function checkTop( cl )

If it's not possible in JSDOC, but possible in typescript, that would be helpful also, but I prefer JSDOC solution.

like image 242
Vincent Avatar asked Jun 29 '19 05:06

Vincent


1 Answers

Define the template as a type you need to return and the parameter as a constructor of that type

/**
* @template {Base} T
* @param {new T} cl
* @returns {T}
*/
function checkTop( cl ) {
    if ( t instanceof cl ) {
        return t;
    }
    return undefined;
}

The result will be:

function checkTop<T extends Base>(cl: new () => T): T
like image 133
Antal Alin Avatar answered Nov 15 '22 21:11

Antal Alin