microsoft / microsoft/TypeScript
Declaration emit: JSDoc @typedef/@callback comments are separated from their synthesized type when preceded by another declaration
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.3k
- Ø Merge
- 2 T. 4 Std.
- Gemergte PRs (30 T.)
- 132
Beschreibung
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.
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Reproduziere beide Snippets im TypeScript Playground im JS-Modus mit aktivierter Declaration-Erzeugung und führe dann lokal tsc --allowJs --declaration --emitDeclarationOnly a.js aus. Da keine Quelldatei oder kein Testpfad angegeben ist, verfolge vor dem Hinzufügen eines Regressionstests, wie der Declaration-Emit synthetisierte JSDoc-@typedef- und @callback-Typen verarbeitet. Als erledigt gilt, wenn jeder emittierte Typ seinen eigenen Kommentar behält und die konsumierende Funktion ihn nicht mehr erhält.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- javascript, typescript
- Bereich
- compilers
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 52/100