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

@template {Ctor} [C = Ctor<typeof Complex>] #2384

Closed
GoToLoop opened this issue Sep 2, 2023 · 3 comments
Closed

@template {Ctor} [C = Ctor<typeof Complex>] #2384

GoToLoop opened this issue Sep 2, 2023 · 3 comments
Labels
bug Functionality does not match expectation

Comments

@GoToLoop
Copy link

GoToLoop commented Sep 2, 2023

Search terms

@template, @typedef, typeof

Expected Behavior

Create doc.

Actual Behavior

Fails to create doc.

Steps to reproduce the bug

Environment

  • Typedoc version: 0.25.0
  • TypeScript version: 5.2.2
  • Node.js version: 9.8.1
  • OS: Windows 8.1

Minimal MJS code:

// @ts-check

/**
 * @typedef {Int8Array | Uint8Array | Uint8ClampedArray | Int16Array |
 * Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array |
 * BigInt64Array | BigUint64Array} TypedArray
 * A union type representing all possible TypedArrays.
 */

/**
* @template {Typed} [T = Typed<TypedArray>]
* @typedef {T} Typed A generic type representing a TypedArray.
*/

/**
 * @template {Ctor} [C = Ctor<typeof Complex>]
 * @typedef {C} Ctor A generic type representing a `Complex` constructor.
 */

/**
 * @template {Ctor} C
 * @typedef {InstanceType<C>} Cinst
 * A generic type representing an instance of a constructor `C`.
 */

/**
 * @template {Ctor} C
 * @typedef {Ctor<C> | {} | void} Cvoid
 * A union type representing either a constructor `C`, an object, or void.
 * Used to hint that a static method can also be invoked "bare".
 */

/**
 * @template T
 * @typedef {new (...args: any) => T} Newable
 * A constructor type that can be instantiated with the `new` keyword.
 */

/**
 * An immutable complex number with real and imaginary parts.
 * @class Complex
 */
export default class Complex {
    /**
     * Create a new instance of the Complex class.
     * @constructor
     * @param {number} [re=0] - The real part of the complex number.
     * @param {number} [im=0] - The imaginary part of the complex number.
     */
    constructor(re = 0, im = 0) {
        /**
         * The real part of the complex number.
         * @readonly
         * @const
         * @type {number}
         */
        this.real = +re || 0;

        /**
         * The imaginary part of the complex number.
         * @readonly
         * @const
         * @type {number}
         */
        this.imag = +im || 0;
    }

    /**
     * Static property's name to check if some constructor is of type Complex.
     * @protected
     * @static
     * @readonly
     * @const {'fromRI'}
     */
    static _METHOD = 'fromRI';

    /**
     * Check if a function is a Complex datatype constructor.
     * @protected
     * @static
     * @template {Ctor} C - Extends typeof Complex.
     * @param {Cvoid<C>} c - The constructor function to check.
     * @return {c is Newable<Cinst<C>>}
     * True if param c is or inherits from Complex class.
     */
    static _isComplex(c) {
        return !!c && Complex._METHOD in c;
    }

    /**
     * Get input constructor c if typeof Complex; or fallback to Complex.
     * @protected
     * @static
     * @template {Ctor} C - Extends typeof Complex.
     * @template {Newable<Cinst<C>>} N - Constructor for typeof Complex.
     * @param {Cvoid<C>} c - The constructor function to verify.
     * @return {N} Param c if type Complex; otherwise a Complex constructor.
     */
    static _ctor(c) {
        return /** @type {N} */ (Complex._isComplex(c) ? c : this || Complex);
    }

    /**
     * Create a new instance of a given Complex constructor function.
     * @protected
     * @static
     * @template {Ctor} C - Extends typeof Complex.
     * @param {Cvoid<C>} c - An existing Complex constructor.
     * @param {*} args - Real & imaginary number parts.
     * @return {Cinst<C>} A new instance of a complex number.
     */
    static _new(c, ...args) {
        return new (this._ctor(c))(...args);
    }
}

TypeDoc doesn't like these 2 @template tags:

/**
* @template {Typed} [T = Typed<TypedArray>]
* @typedef {T} Typed A generic type representing a TypedArray.
*/

/**
 * @template {Ctor} [C = Ctor<typeof Complex>]
 * @typedef {C} Ctor A generic type representing a `Complex` constructor.
 */

It fails to complete the task w/ these 2 errors:

[error] Failed to find JSDoc tag for T after parsing comment, please file a bug report.

[error] Failed to find JSDoc tag for C after parsing comment, please file a bug report.

As a workaround, I could move those 2 inside the class itself.
Doing so, TypeDoc fully runs and outputs the doc.
However, it'll simply ignore the existence of both @template tags!
It then displays this extra warning btw:

[warning] Ctor, defined in ./complex.mjs, is referenced by Cvoid but not included in the documentation.

I wonder if there's some other alternative syntax to constrain a type to Complex type and any possible subclass of it...

@GoToLoop GoToLoop added the bug Functionality does not match expectation label Sep 2, 2023
@Gerrit0
Copy link
Collaborator

Gerrit0 commented Sep 3, 2023

Couple bugs here:

  1. TypeDoc doesn't handle spaces when trying to handle defaulted type parameters in JSDoc, not quite sure how I missed this, probably something to do with how JSDoc is a terrible world where everything is a hack...
  2. TypeDoc doesn't recognize constraints on @template tags, because for some horrid reason, TypeScript doesn't set the TypeParameter.constraint property like it does for normal TS

@GoToLoop
Copy link
Author

GoToLoop commented Sep 3, 2023

2. , TypeScript doesn't set the TypeParameter.constraint property like it does for normal TS.

Indeed, when I compile the types of the JSDoc ".mjs" file to "d.mts" type file, @template Ctor doesn't show up!

However, everything else works! TS has no problem inferring Ctor for all methods relying on it. And hovering tips work pretty well too.

Anyways, I've decided to abandon JSDoc hacked defaulted parameter type until TS is fully compliant.

This is what I'm using now. Not as good though b/c passing a type argument is required:

/**
 * @typedef {typeof Complex} TC
 */

/**
 * @template {Ctor<TC>} C
 * @typedef {C} Ctor A generic type representing a `Complex` constructor.
 */

/**
 * @template {TC} C
 * @typedef {InstanceType<C>} Cinst
 * A generic type representing an instance of a constructor `Complex`.
 */

/**
 * @template {Ctor<TC>} C
 * @typedef {Ctor<C> | {} | void} Cvoid
 * A union type representing either a constructor `Complex`, an object, or void.
 * Used to hint that a static method can also be invoked "bare".
 */

/**
 * @typedef {Int8Array | Uint8Array | Uint8ClampedArray | Int16Array |
 * Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array |
 * BigInt64Array | BigUint64Array} TypedArray
 * A union type representing all possible TypedArrays.
 */

/**
 * @template {Typed<TypedArray>} T
 * @typedef {T} Typed A generic type representing a TypedArray.
 */

@GoToLoop GoToLoop closed this as completed Sep 3, 2023
@Gerrit0
Copy link
Collaborator

Gerrit0 commented Sep 3, 2023

I still want to fix the first issue, that's an issue in typedoc

the second one I plan to open an issue in the TS repo for

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Functionality does not match expectation
Projects
None yet
Development

No branches or pull requests

2 participants