microsoft / microsoft/TypeScript

Declaration emit: JSDoc @typedef/@callback comments are separated from their synthesized type when preceded by another declaration

Abierto
#63,958 4 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Bug
Lenguaje dominante
Go
Estrellas
111k
Forks
14.3k
Merge medio
2 d 4 h
PR fusionados (30 d)
132

Descripción

Search Terms

jsdoc typedef declaration order, typedef hoisted end of file, callback comment lost, allowjs declaration emit typedef comment

Version & Regression Information

Reproduces identically on 5.9.3 and 7.0.2 — not a regression. I searched the tracker and couldn't find an exact match; closest are #62453 ("JSDoc comments emitted a second time") and the now-closed #62979 ("Fix duplicate JSDoc @typedef and @callback comments"), but those describe duplication, whereas this is a misplacement/loss.

Playground Link

(paste either repro below into the TypeScript Playground, switch to "JS" mode, enable "declaration" in the config gear, and check the .D.TS tab)

Repro 1 — @typedef gets hoisted to the end of the file, comment does not move with it:

export function noop() {}

/**
 * @typedef {Object} Point
 * @property {number} x
 * @property {number} y
 */

/**
 * @param {Point} p
 */
export function dist(p) {
  return p.x;
}

Compiled with: tsc --allowJs --declaration --emitDeclarationOnly a.js

Repro 2 — @callback stays in its correct position, but still loses its comment:

export function noop() {}

/**
 * @callback Comparator
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */

/**
 * @param {number[]} arr
 * @param {Comparator} cmp
 */
export function sortWith(arr, cmp) {
  return arr.slice().sort(cmp);
}

Actual output:

```ts
export declare function noop(): void;
export type Comparator = (a: number, b: number) => number;
/**

  • @callback Comparator
  • @param {number} a
  • @param {number} b
  • @returns {number}
    /
    /
    *
  • @param {number[]} arr
  • @param {Comparator} cmp
    */
    export declare function sortWith(arr: number[], cmp: Comparator): number[];
    ```

Here Comparator lands in the correct position (right after noop), but its doc comment is left behind above sortWith instead of attached to the type it describes.

When a JSDoc @typedef or @callback is preceded by another top-level declaration in the source file, declaration emit separates the JSDoc comment from the type it documents.

For Repro 1, the actual output is:

export function noop(): void;
/**
 * @typedef {Object} Point
 * @property {number} x
 * @property {number} y
 */
/**
 * @param {Point} p
 */
export function dist(p: Point): number;
export type Point = {
    x: number;
    y: number;
};

Point is emitted at the very end of the file, but its comment is left in its original position, directly above dist. Result: dist looks documented with a comment that actually describes Point, and Point itself has no documentation.

For Repro 2, the actual output is:

export declare function noop(): void;
export type Comparator = (a: number, b: number) => number;
/**
 * @callback Comparator
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
/**
 * @param {number[]} arr
 * @param {Comparator} cmp
 */
export declare function sortWith(arr: number[], cmp: Comparator): number[];

Here Comparator lands in the correct position (right after noop), but its comment is still left behind above sortWith instead of attached to Comparator.

In both cases the underlying issue is the same: whatever step attaches leading comments to declarations during .d.ts emission is not correctly following the type when it's synthesized from a JSDoc tag, once there's a preceding sibling declaration to get confused with. This is wrong because .d.ts output is documentation-facing — consumers read these comments in editor hover tooltips — so misattributed or missing docs are a real, user-visible regression, not a cosmetic quirk.
The JSDoc comment for a @typedef or @callback should stay attached to the declaration it documents in the emitted .d.ts, regardless of what other declarations appear earlier in the file.

For Repro 1, I'd expect either Point to keep its natural position in the output (immediately after noop, with its comment directly above it), or, if it must be hoisted to the end, its comment should be hoisted along with it — the two should never be split apart.

For Repro 2, I'd expect the Comparator type (already emitted in the correct position) to carry its own comment with it, rather than leaving that comment stranded above sortWith.

This matters because declaration emit exists to preserve type information and documentation for consumers of a package — someone hovering over Point or Comparator in their editor should see the description of that type, not nothing, and someone hovering over dist or sortWith shouldn't see documentation written for a different symbol.

Note: this only reproduces when at least one other top-level declaration precedes the @typedef/@callback block. A file with only the tag and the function using it emits correctly.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Reproduce ambos fragmentos en TypeScript Playground en modo JS con la declaración habilitada y luego ejecuta localmente tsc --allowJs --declaration --emitDeclarationOnly a.js. No se indica ningún archivo fuente ni ruta de prueba, así que rastrea cómo el emit de declaraciones gestiona los tipos @typedef y @callback de JSDoc sintetizados antes de añadir una prueba de regresión. Se considera terminado cuando cada tipo emitido conserva su propio comentario y la función consumidora deja de recibirlo.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
javascript, typescript
Área
compilers
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Activo
Claridad
Bastante claro
Aptitud para principiantes
52/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.