12

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.

7
  • Cannot reproduce. Console shows an object of type Derived for d1, and undefined for d2. Perhaps I'm misunderstanding something? Commented Jul 4, 2019 at 5:23
  • @Chipster I'm using vscode and it's recognized as 'typeof Derived2' for d2. I've added screenshots. The return type is T which extends {typeof Base} so it should at least have a 'typeof something'. But I want to remove the 'typeof' and recognize the return type as just an instance. Commented Jul 5, 2019 at 0:49
  • 'typeof Derived1' returns {} and null for the 'typeof Derived2', checkTop() function will always return the type of the variable because you pass a class that is invoked all ready, you can return the 'cl' of Derived the class declared Commented Jul 6, 2019 at 3:30
  • class Derived extends Base {} console.log(Derived); // returns a function(){...} console(new Derived()); ///returns object {} //becuase it was already invoked Commented Jul 6, 2019 at 3:33
  • Maybe that way stackoverflow.com/questions/21002316/… because basically you are returning an object which is just an instance. Meanwhile, you want to show a returning type. The type is object. You can specify that it's an instance of an object in a comment. Commented Jul 8, 2019 at 19:01

6 Answers 6

7

Define the template as a type you need to return. You can declare type parameters with the @template tag. This lets you make functions, classes, or types that are generic. See Typescript docs

/**
* @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
Sign up to request clarification or add additional context in comments.

2 Comments

A short explanation could be useful.
This solved my issue. T = (Class1 | Class2) and S was my template. Intellisense would show both Class1 and Class2 prototypes but doing new S would show the one that was inserted into the parameter.
0

I may be misunderstanding the ask here, but I think you just need to return cl instead of returning t:

/**
 * @template {typeof Base} T
 * @param {T} cl
 * @returns {T}  /// <-- I can't figure out how o return an instance of T
 */
function checkTop( cl ) {
    if ( t instanceof cl ) {
        return cl;
    }
    return undefined;
}

1 Comment

My intention is to 'return t' and change return type to reflect it: somehow specifying the return type is an instance of cl.
0

You've asked for case if it's possible at least in a TypeScript. Yes it is. Just remove your JSDoc comment and you will have a suggestion you are looking for.

For clearance you can just make a comment which only says of what it returns. That's enough.

enter image description here enter image description here

You were just rewriting the correct TypeScript suggestions by your assertions (the programmer's opinion is considered to be more important that TypeScript's suggestion since the programmer knows what he's doing when specifying something explicitly).

1 Comment

what about const d2 = chekTop(Derived2)? I want type of d2 to be recognized as Derived2.
0

So I read about jsdocs on internet and here is my conclusion I found the required result

See the screenshot and feel happy, issue resolved.

enter image description here

So what helps in the jsDocs

/**
 * @typedef {Object} 
 * @param {c1}
 */

here is the code snippet

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

class Derived extends Base {
}

class Derived2 extends Base {
}

var t = new Derived();
var t1 = new Derived2();

/**
 * @typedef {Object} 
 * @param {c1}
 */
function checkTop( cl ) {
  if ( t instanceof cl ) {
      return t;
  }
  return undefined;
}

/**
 * @typedef {Object} 
 * @param {c1}
 */
function checkTop2( cl ) {
  if ( t1 instanceof cl ) {
      return t1;
  }
  return undefined;
}
var d1 = checkTop(Derived);
var d2 = checkTop2(Derived2);

3 Comments

I want a single checkTop function. t can be changed at runtime.
I just write checkTop function for referance (Just to show you), if you write single function and change t at run time, it will work fine, Just try this jscode template
I tried but it doesn't work. checkTop( Derived2 ) has a return type of Derived not Derived2 as I wanted. @typedef is doing nothing and there's no @return.
0

Here is how I was able to accomplish this... The constructor type should be typed as {new() => T}

/**
 * @template {Base} T
 * @param {new() => T} cl
 * @returns {T}
 */
function checkTop( cl ) {
    if ( t instanceof cl ) {
        return t
    }
    
    // You should always return an instance
    // of cl unless the return type is {?T}
    return new cl()
}

Comments

-1

You can try Typescript Generics to implement what you want to achieve and it's good to use Typescript feature instead of JSDOCS

Try following code and its working fine.

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

   class Derived2 extends Base {}
  
   var t : Derived = new Derived();
   var t1 : Derived2= new Derived2();
  
   function checkTop <GT>(genericValue: GT){
       return genericValue;
   }

   var d1 = checkTop(t);
   var d2 = checkTop(t1);

enter image description here


OR

After spending some time learning TypeScript, I get to know we about type

declare type A = { id: string }
declare type B = { name: string }

function get<T>(obj: T): T {
    return obj;
}

var obj1: A = {id : "Jarvis"};
var obj2: B = {name : "Tony Stark"};

var objectTypeA = get(obj1);


var objectTypeB = get(obj2);

enter image description here

Comments

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.