Skip to content

Exported const type parameters is not renamed in constraint in another const in type declarations #56783

@mcheshkov

Description

@mcheshkov

🔎 Search Terms

Generic methods
Constraints
Type parameters renaming
Type declarations

🕗 Version & Regression Information

⏯ Playground Link

https://www.typescriptlang.org/play?target=7&allowSyntheticDefaultImports=false&ts=5.3.2#code/C4TwDgpgBACgTAHgDIBooCUB8UC8UlQBkUA3lANoDSUAlgHZQDWEIA9gGYYC6AXFHQFcAtgCMIAJygBfANwBYAFCLQkWAgAq2PGSq0GzNp3W9+wsZKmLFAY1Z0AzsCgAxVq1ylFUb1HYIAklAQAB7AEHQAJvawiCRSaP6YmAAUAJSk8V4+AOYBQaHhUWqJKelxKIqyVgq2Dk4AQgCGktpZ3n6BIWGR0fAI5VAlaRkVCj5QuZ0FPcVJw+WV8koKIWCs4k61jlBNAF4eJG2+eV2FvbHxg3NlmWM5J9NFMAHXI4vVq+ubdtsAIhCcVp3dpuPiuVijcYiZp8JriSE+aG7WGNXajKrLIA

💻 Code

type P2<L, R> = L & { [K in keyof R]: number };

type P<T> = { [K in keyof T]: number }

const Foo = {
    f<I extends P2<{}, I>>() {},
    g<I extends P<I>>() {},
};

const Bar = {
    f<I extends P2<{}, I>>() {},
    g<I extends P<I>>() {},
};

export const Baz = {
    f<I extends P2<{}, I>>() {},
    g<I extends P<I>>() {},
};

export const Def = {
    foo: Foo,
    bar: Bar,
    baz: Baz,
};

🙁 Actual behavior

Generated .d.ts on v5.3.2 looks like this:

type P<T> = {
    [K in keyof T]: number;
};
export declare const Baz: {
    f<I extends { [K in keyof I]: number; }>(): void;
    g<I_1 extends P<I_1>>(): void;
};
export declare const Def: {
    foo: {
        f<I extends { [K in keyof I]: number; }>(): void;
        g<I_1 extends P<I_1>>(): void;
    };
    bar: {
        f<I_2 extends { [K_1 in keyof I_2]: number; }>(): void;
        g<I_3 extends P<I_3>>(): void;
    };
    baz: {
        f<I_4 extends { [K in keyof I]: number; }>(): void;
        g<I_5 extends P<I_5>>(): void;
    };
};
export {};

Notice the line f<I_4 extends { [K in keyof I]: number; }>(): void; in baz, there's no I in scope.
Same line in bar, that's f<I_2 extends { [K_1 in keyof I_2]: number; }>(): void; has type parameters correctly renamed, which points to exported consts specifically.
g<I_5 extends P<I_5>>(): void; also have correct type params, so simple generic type like P is not enough.

🙂 Expected behavior

Generated .d.ts on v4.3.5 looks like this:

declare type P<T> = {
    [K in keyof T]: number;
};
export declare const Baz: {
    f<I extends { [K in keyof I]: number; }>(): void;
    g<I_1 extends P<I_1>>(): void;
};
export declare const Def: {
    foo: {
        f<I extends { [K in keyof I]: number; }>(): void;
        g<I_1 extends P<I_1>>(): void;
    };
    bar: {
        f<I_2 extends { [K_1 in keyof I_2]: number; }>(): void;
        g<I_3 extends P<I_3>>(): void;
    };
    baz: {
        f<I_4 extends { [K_2 in keyof I_4]: number; }>(): void;
        g<I_5 extends P<I_5>>(): void;
    };
};
export {};

Notice the line f<I_4 extends { [K_2 in keyof I_4]: number; }>(): void;, all type parameters nave been correctly renamed.

Additional information about the issue

Bisected commit passes sniff test: it introduces type caching and accessibility tracking, so maybe some of that triggers when emitting first constant, and poisons cache for visitDeclarationSubtree -> ... -> signatureToSignatureDeclarationHelper -> ... -> typeParameterToDeclaration call later

Origin of this issue is code generated by ts-proto with outputServices=generic-definitions option. See gist for example. Problem occuring here, on lines 70-79 in a.d.ts, where create and fromPartial have renamed type parameter, but original constraint (seemingly, from export declare const FooResponse)

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptDomain: Declaration EmitThe issue relates to the emission of d.ts files

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions