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
likewise, d2 is recognized as 'typeof Derived2'
let d2 = checkTop( Derived2 ); // 'typeof Derived2'.. but I want 'Derived2' as return type
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.
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
likewise, d2 is recognized as 'typeof Derived2'
let d2 = checkTop( Derived2 ); // 'typeof Derived2'.. but I want 'Derived2' as return type
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.
Share Improve this question edited Aug 5, 2020 at 16:09 Dupinder Singh 7,7698 gold badges40 silver badges64 bronze badges asked Jun 29, 2019 at 5:33 VincentVincent 3,5094 gold badges31 silver badges35 bronze badges 7- Cannot reproduce. Console shows an object of type Derived for d1, and undefined for d2. Perhaps I'm misunderstanding something? – user10957435 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. – Vincent 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 – bdalina 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 – bdalina 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. – Sergey Commented Jul 8, 2019 at 19:01
6 Answers
Reset to default 7Define 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
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;
}
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.
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).
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.
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);
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()
}
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);
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);