Typescript: Compiler outputs invalid TypeScript code when provided JS code with JSDoc Callbacks

Created on 14 Apr 2020  路  4Comments  路  Source: microsoft/TypeScript

TypeScript Version: 3.8.3


Search Terms: jsDoc callback

Expected behavior: I'm attempting to generate TS definition files from a fairly large JavaScript codebase that makes meticulous use of JSDoc comments. I ran into an issue with JSDoc style callback definitions, which rely on the tilde, ~. Basically, TS should interpret the callback correctly and produce valid definitions. For my sample code, I would expect something like the below:

export default TextureAtlas;
export type TextureAtlasCreateImageCallback = () => any;
/**
 * @alias TextureAtlas
 * @constructor
 */
declare function TextureAtlas(options: any): void;
declare class TextureAtlas {
    /**
     * @alias TextureAtlas
     * @constructor
     */
    constructor(options: any);
    passCallback(callback: TextureAtlasCreateImageCallback): any;
}

Or even better, make CreateImageCallback a member of TextureAtlas

Actual behavior: It outputs invalid TS code that truncates the callback name

export default TextureAtlas;
/**
 * ~CreateImageCallback
 */
export type TextureAtlas = () => any;
/**
 * @alias TextureAtlas
 * @constructor
 */
declare function TextureAtlas(options: any): void;
declare class TextureAtlas {
    /**
     * @alias TextureAtlas
     * @constructor
     */
    constructor(options: any);
    passCallback(callback: any): any;
}

Removing the ~ from the source JS code and JSDoc dramatically changes the output.


Related Issues: No

Code

/**
 * @alias TextureAtlas
 * @constructor
 */
function TextureAtlas(options) {
}

/**
 * @param {TextureAtlas~CreateImageCallback} callback
 */
TextureAtlas.prototype.passCallback = function(callback) {
    return callback();
}

/**
 * @callback TextureAtlas~CreateImageCallback
 * @returns {Image} The image
 */

export default TextureAtlas;

Output

export default TextureAtlas;
/**
 * ~CreateImageCallback
 */
export type TextureAtlas = () => any;
/**
 * @alias TextureAtlas
 * @constructor
 */
declare function TextureAtlas(options: any): void;
declare class TextureAtlas {
    /**
     * @alias TextureAtlas
     * @constructor
     */
    constructor(options: any);
    passCallback(callback: any): any;
}

Compiler Options

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": false,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "useDefineForClassFields": false,
    "alwaysStrict": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "downlevelIteration": false,
    "noEmitHelpers": false,
    "noLib": false,
    "noStrictGenericChecks": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "esModuleInterop": true,
    "preserveConstEnums": false,
    "removeComments": false,
    "skipLibCheck": false,
    "checkJs": true,
    "allowJs": true,
    "declaration": true,
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false,
    "target": "ES5",
    "module": "ES2015"
  }
}

Playground Link: Provided

Bug

All 4 comments

@RyanCavanaugh we very explicitly do not support jsdoc namepaths (beyond instructing the parser how to skip over them), and Thing~Whatever is definitely a jsdoc namepath.

Thanks @weswigham so I assume that means this will not be supported anytime soon? I just found it odd that it generates invalid TS and doesn't output any kind of warnings (but I'm relatively new to TS so I still have a lot to learn).

The documentation (https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#supported-jsdoc) doesn't say anything about namepaths, just that @callback is explicitly supported. So it would be nice if it were updated to reflect JSDoc limitations more completely.

Is there any recommendation on how to modify our use of JSDoc to better accommodate the TS compiler? Simply removing the ~ character sort of works because it turns it into a global callback function, but it changes the doc output in non-trivial ways.

Write the TS-compatible type references that refer to things instead - usually NamespaceThing.ExportWhatever for lookups/declarations, but ClassThing["instance member"], and import("mod").ExportThing may also be useful for looking up things.

Thanks, I can't believe I didn't notice that replacing ~ with . worked (with seemingly no ill affects on the jsDoc side).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

manekinekko picture manekinekko  路  3Comments

seanzer picture seanzer  路  3Comments

bgrieder picture bgrieder  路  3Comments

CyrusNajmabadi picture CyrusNajmabadi  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments