Repository: TypeScript
Issue: Type literals in declaration files are emitted with comment blocks from the wrong source file
Labels: Needs Investigation,Domain: Comment Emit

### 🔎 Search Terms

"comments", "comment emit", "declaration comments", "inconsistent comments", ".d.ts comment", ".d.ts jsdoc", "wrong file", "crlf"

### 🕗 Version & Regression Information

- This is the behavior in every version I tried, and I reviewed the FAQ for entries about comments


### ⏯ Playground Link

https://www.typescriptlang.org/dev/bug-workbench/?noLib=true&esModuleInterop=false&target=8&sourceMap=true&declarationMap=true&inlineSources=true&generateTrace=true&ts=5.4.4#code/PTAEAEBMFMGMBsCGAnRAXAlgewHYC5Q1kBXaAKBAgGcALLAdwFEBbDNCscWhlttaSADEM8aAQBGKAHSQpaKhwgAzEdByJmY0EqxY5CygHlBggMqMAKlOs3bd+w6lloADwAOWZGlCxcVb1jiAFagALygAN5koKDAAFRxoADCWMyaON46yKAABm7IWG45oHHA0aD5hQQARNUANGQAvgDcZIrgKqLqmhLS8mQYzB5ekaCBIY3aBcyg1VLAOljVrc7unt6+OP6gLmGR5QCCBOMN5fGJKWlqmZ65AELFpeV3x8ENMeVJr0ENLWRAA

### 💻 Code

```ts repro
// @declaration: true
// @showEmit
// @showEmittedFile: bar.d.ts
// @filename: foo.ts
// OFFSET.............................
export const obj = {
  /** Comment for `prop` */
  prop: "",
};

// @filename: bar.ts
import { obj } from "./foo";

export const x = {
  A: obj,

  /** Comment for `B` */
  B: obj,
  
  C: obj,
};

```

[Workbench Repro](https://www.typescriptlang.org/dev/bug-workbench/?noLib=true&esModuleInterop=false&target=8&sourceMap=true&declarationMap=true&inlineSources=true&generateTrace=true&ts=5.4.4#code/PTAEAEBMFMGMBsCGAnRAXAlgewHYC5Q1kBXaAKBAgGcALLAdwFEBbDNCscWhlttaSADEM8aAQBGKAHSQpaKhwgAzEdByJmY0EqxY5CygHlBggMqMAKlOs3bd+w6lloADwAOWZGlCxcVb1jiAFagALygAN5koKDAAFRxoADCWMyaON46yKAABm7IWG45oHHA0aD5hQQARNUANGQAvgDcZIrgKqLqmhLS8mQYzB5ekaCBIY3aBcyg1VLAOljVrc7unt6+OP6gLmGR5QCCBOMN5fGJKWlqmZ65AELFpeV3x8ENMeVJr0ENLWRAA)

### 🙁 Actual behavior

The emitted `bar.d.ts` declaration file includes the comment on line 17 (preceding the `B` property assignment in `bar.ts`) above each `prop` signature:
```ts
export declare const x: {
    A: {
        /** Comment for `B` */
        prop: string;
    };
    /** Comment for `B` */
    B: {
        /** Comment for `B` */
        prop: string;
    };
    C: {
        /** Comment for `B` */
        prop: string;
    };
};
```
Note that the `OFFSET...` comment on line 5 (in its entirety) is necessary to reproduce this behavior.  This just so happens to align the start of the comment range for the `prop` assignment in `foo.ts` (63) one character past the start of the `B` assignment's comment range in `bar.ts` (62).

Strangely, if I remove a single character from line 5 (so that both comment range starts are perfectly aligned), the comment above `B.prop` is omitted, but the others remain:
```ts 
export declare const x: {
    A: {
        /** Comment for `B` */
        prop: string;
    };
    /** Comment for `B` */
    B: {
        prop: string;
    };
    C: {
        /** Comment for `B` */
        prop: string;
    };
};
```

Any _other_ changes to the number of characters preceding the object literal expression in `foo.ts` results in the expected `bar.d.ts`:
```ts
export declare const x: {
    A: {
        prop: string;
    };
    /** Comment for `B` */
    B: {
        prop: string;
    };
    C: {
        prop: string;
    };
};
```

### 🙂 Expected behavior

_Ideally_, the emitted `bar.d.ts` declaration file should include the correct comments for all property signatures:
```ts
export declare const x: {
    A: {
        /** Comment for `prop` */
        prop: string;
    };
    /** Comment for `B` */
    B: {
        /** Comment for `prop` */
        prop: string;
    };
    C: {
        /** Comment for `prop` */
        prop: string;
    };
};
```
But I understand from the FAQ that might have a performance impact.  In that case, I would expect the `bar.d.ts` file to _consistently_ omit comments for type literals defined outside `bar.ts`:
```ts
export declare const x: {
    A: {
        prop: string;
    };
    /** Comment for `B` */
    B: {
        prop: string;
    };
    C: {
        prop: string;
    };
};
```
In other words, the compiler should handle this corner case where comment positions just happen to align across multiple files.  The current behavior can lead to weird declaration file inconsistencies across platforms (due to CR characters potentially aligning/mis-aligning comment ranges on Windows only).

### Additional information about the issue

A couple other observations:
- This is only reproducible with a JSDoc-style comment block (`/**`) in `bar.ts`
- Changing or removing the comment for `prop` on line 7 has no effect on the emitted `bar.d.ts`
- This appears to happen anytime a type defined in `foo.ts` is substituted for an expression in `bar.ts` (and comment ranges align).  For example, [here's another repro](https://www.typescriptlang.org/dev/bug-workbench/?noLib=true&esModuleInterop=false&target=8&sourceMap=true&declarationMap=true&inlineSources=true&generateTrace=true&ts=5.4.4#code/PTAEAEBMFMGMBsCGAnRAXAlgewHYC5Q1kBXaAKBAgGcALLAdwFEBbDNCscWhlttaSADEM8aAQBGKAHSQpaKhwgAzEdByJmY0EqxY5CygHlBggMqMAKlOs3bd+w8dSy0AB4AHLMjTbiOWJi4oLDI0OjQjK4a7qIAFO7IWO4EVEQYOADmAJSgAN5koKChaMTIOHkFhaDAAFQ1oADCWMyaOD46yKAABglJXaA1wJWFvcmgowA0lQC+ANxk02SK4Cqi6poS0vJkGMye3nnBoeGR0aKg09qJzKAARFLAOli38y4eXj6wuKmgp3uihnEACs4PJQABeCqFQEggIAQQIITC-D+MWgsVucNuWSmlVq9SaLTU7S83RhoIAQv1BpVyQEKYjjiiov90bcKdjcdDgaCGozkREWWiMQ1OQt5kA) showing similar behavior when `bar.ts` includes calls to a function (returning an object literal) defined in `foo.ts`, and [yet another](https://www.typescriptlang.org/dev/bug-workbench/?noLib=true&esModuleInterop=false&target=8&sourceMap=true&declarationMap=true&inlineSources=true&generateTrace=true&ts=5.4.4&ssl=15&ssc=1&pln=27&pc=1#code/PTAEAEBMFMGMBsCGAnRAXAlgewHYC5Q1kBXaAKBAgGcALLAdwFEBbDNCscWhlttaSADEM8aAQBGKAHSQpaKhwgAzEdByJmY0EqxY5CygHlBggMqMAKmWgAPAA5ZkabcRyxMuULGTR00RjYadqIAwkhUVAAUANYYOJAEVERxAOYANKB2yFh2ick4KQCUoADeZKCgPmjEyDhe4VSl5RWZxOLwGLCgSeidoLHxoAC8-XGQANzNFcAAVDOgIVjMmjjOOsigAAZZOZugiLCw0BGOoDPAU63tfSnQzjt2kYV5yKmllXc1dQ-joAC+zT+kwBinAKlE6k0Emk8jIGGYDicTRa3l8-ACQVCDQyoDIf202WYoAARFJgDosMTJtZ7I5nLBcElQBiEVjEBFjsNkQsGgBBAiovws4LQMLsqLE3nEjLE4mFNJkZqzeaLZZqNanTZiiIAIT252a2qoOoFPiFgVZooakWJOulJLlCoqhoaIVNaP8FpFRptIXtsvleMmQA) where said function returns a class expression instead.