Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support typedef inheritance with JSDoc #20077

Open
fongandrew opened this issue Nov 16, 2017 · 9 comments
Open

Support typedef inheritance with JSDoc #20077

fongandrew opened this issue Nov 16, 2017 · 9 comments
Labels
Domain: JSDoc Relates to JSDoc parsing and type generation In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@fongandrew
Copy link

TypeScript Version: 2.7.0-dev.20171116

Code

/**
 * @typedef {Object} Base
 * @property {String} baseProp
 */

/**
 * @typedef {Base} Child
 * @property {String} childProp
 */

/** @type {Child} */
const child = { baseProp: '' };

Expected behavior: Error. child is missing the childProp property.

Actual behavior: No error. The Child type is identical to the Base type and only requires a baseProp property. The childProp property definition is completely ignored.

Or maybe there's another way to do the equivalent of interface Child extends Base here?

@fongandrew
Copy link
Author

For what it's worth, I also tried the following combinations. Both result in Child being typed as any.

/**
 * @typedef {Object} Child
 * @extends Base
 * @property {String} childProp
 */
/**
 * @typedef {Object} Child
 * @mixes Base
 * @property {String} childProp
 */

@mhegazy mhegazy added Domain: JSDoc Relates to JSDoc parsing and type generation Suggestion An idea for TypeScript labels Nov 17, 2017
@ekulabuhov
Copy link

You can use an Intersection Type notation there:

/**
 * @typedef {Base & {childProp: String}} Child
 */

or

/**
 * @typedef {Object} ChildType
 * @property {String} childProp
 *
 * @typedef {Base & ChildType} Child
 */

should both work.

@kasora
Copy link

kasora commented May 31, 2018

@ekulabuhov life saver!

@mmis1000
Copy link

mmis1000 commented Jun 15, 2018

Although the & trick works most of time.
Some things will only work with interface instead of type

// won't work, and no workaround at all

/**
 * @typedef {number|ArrayjOfValue} value
 */

/**
 * @typedef {Array<value>} ArrayjOfValue
 */

/**
 * @type {value}
 */
var k1 = [1, [1]]
// works

type value = number | ArrayOfValue;

interface ArrayOfValue extends Array<value> {}

var k1: value = [1, [1]]

The interface in typescript is lazy evaluated.
And only checked when the value is actually encountered.
So, it can work as a guard to prevent the definition from expanding infinitely.

While the type is not.
And will be expanded completely at init time.
Making referring to itself not possible at all.

I think typedef in JSDOC extends from non Object Object type should be translate to a interface instead of a type definition.

Or it will make the JSDOC syntax lack a bunch of ability

But I don't have any idea whether it will break existing code or not. And whether interface can be a superset of type or not.

@brettz9
Copy link

brettz9 commented Jul 2, 2018

For JSDoc code already using this, it'd be nice to have compatibility. Same for interface/implements....

@myfonj
Copy link

myfonj commented Feb 7, 2019

(Pardon perhaps silly question regarding JSDoc behavior in current VSCode.)

"Intersection Type notation" from ekulabuhov's comment somewhat works in current VSCode but only when used like

/**
 * @typedef movable
 * @property {function} moveMe
 */
/**
 * @typedef {movable & HTMLElement} movableElement
 */
/** @type movableElement */
var myElement = document.querySelector('#myElement');
myElement.moveMe; // OK, function
myElement.tabIndex; // OK, number
myElement.error_test; // OK, does not exist

But straightforward declaration of custom type with base type and custom property

/**
 * @typedef {HTMLElement} movableElement
 * @property {function} moveMe
 */

results in simply aliasing HTMLElement as movableElement but with no added property. (It is basically what OP describes.) So is it a bug or some reasonable behavior? Using TypeScript (hopefully) equivalent

type movableElement = HTMLElement & { moveMe: Function };
var myElement: movableElement = document.querySelector('#myElement');
myElement.tabIndex; // OK, number
myElement.moveMe; // OK, Function
myElement.error_test; // OK, does not exist

works as expected.

BTW, if that Intersection Type notation is standard and stable already, it should be probably mentioned in https://github.com/Microsoft/TypeScript/wiki/JsDoc-support-in-JavaScript (?)

@chriseaton
Copy link

This would be really great as intersection types "&" are not going to to be supported by jsdoc.

@teocns
Copy link

teocns commented Oct 25, 2020

Any valid @jsdoc solution yet?

@tomalec
Copy link

tomalec commented Oct 25, 2021

Is there a way to add a description to the child property created with

/**
 * @typedef {Base & {childProp: String}} Child
 */

without creating a single-serving proxy type with ChildType type?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: JSDoc Relates to JSDoc parsing and type generation In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests