typescripttypescript-genericsmapped-typestypescript-declarationstypescript-language-server

Preserve comments for mapped types in d.ts


In the latest Typescript (v5.0.4 as for today) when I compile declarations for the following code:


type SomeType<T> = {
  field: T;
};

const getInstance = <T>(
  value: T
): SomeType<{
  [K in keyof T]: T[K];
}> => {
  return {
    field: value,
  };
};

export const variable = getInstance({
  /**
   * want to have it in d.ts
   */
  nested: "nested",
});

I'm getting this in my d.ts:

type SomeType<T> = {
    field: T;
};
export declare const variable: SomeType<{
    nested: string;
}>;
export {};

Which reflects what we have in the code, but unfortunately there is no comment. I happens specifically when I use mapped types in the returned type.

It would have been work fine If I don't use mapped type, but unfortunately I can't get rid of it in my case.

The question is how to preserve the comment in the d.ts file with mapped type? Nice stuff is that I see my comment in VSCode when I hover over variable.field.nested property which means that Typescript preserves it somewhere but just doesn't add it to d.ts file on declaration generation stage.


Solution

  • I can't find authoritative documentation for exactly how the compiler chooses to preserve or discard comments in declaration files, but since you said it works fine if you just wrote SomeType<T> instead of SomeType<{[K in keyof T]: T[K]}>, that suggests comments might be preserved when using a generic type directly like XXX<T>. So what if we defined an XXX that behaves how you want?

    // .ts file
    type GetInstance<T> =
        SomeType<{ [K in keyof T]: T[K] }>;
    
    const getInstance = <T,>(value: T
    ): GetInstance<T> => {
        return {
            field: value,
        };
    };
    
    export const variable = getInstance({
        /**
         * want to have it in d.ts
         */
        nested: "nested",
    });
    

    This is equivalent to your code. And when we check the generated declaration file, the comment is indeed preserved!

    // .d.ts file
    export declare const variable: GetInstance<{
        /**
         * want to have it in d.ts
         */
        nested: string;
    }>;
    export {};
    

    If anyone finds where such behavior is documented I'd be happy to add it here.

    Playground link to code