Skip to content

Commit c0703e6

Browse files
authored
Fix declaration emit alias reuse for inferred exports (#3314)
1 parent 02bf7c9 commit c0703e6

10 files changed

Lines changed: 135 additions & 62 deletions

internal/checker/nodebuilderimpl.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ func (b *NodeBuilderImpl) serializeTypeName(node *ast.Node, isTypeOf bool, typeA
319319
if isTypeOf {
320320
meaning = ast.SymbolFlagsValue
321321
}
322-
symbol := b.ch.resolveEntityName(node, meaning, true, true, node)
322+
symbol := b.ch.resolveEntityName(node, meaning, true, false, node)
323323
if symbol == nil {
324324
return nil
325325
}

internal/execute/tsctests/tsc_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,47 @@ func TestTscDeclarationEmit(t *testing.T) {
634634
},
635635
commandLineArgs: []string{"--b", "packages/pkg2/tsconfig.json", "--verbose"},
636636
},
637+
{
638+
subScenario: "when inferred export should reuse imported type alias across a module boundary",
639+
files: FileMap{
640+
"/home/src/workspaces/project/tsconfig.json": stringtestutil.Dedent(`
641+
{
642+
"compilerOptions": {
643+
"strict": true,
644+
"declaration": true,
645+
"emitDeclarationOnly": true,
646+
"target": "es2022",
647+
"module": "esnext",
648+
},
649+
"files": ["./a.ts", "./factory.ts", "./state.ts"],
650+
}`),
651+
tscLibPath + "/lib.es2022.full.d.ts": tscDefaultLibContent + "\n" + stringtestutil.Dedent(`
652+
type Partial<T> = {
653+
[K in keyof T]?: T[K];
654+
};
655+
`),
656+
"/home/src/workspaces/project/a.ts": stringtestutil.Dedent(`
657+
interface ISettings {
658+
age: number;
659+
}
660+
661+
export type Settings = Partial<ISettings>;
662+
`),
663+
"/home/src/workspaces/project/factory.ts": stringtestutil.Dedent(`
664+
import type { Settings } from "./a";
665+
666+
export const makeObj = () => ({
667+
fn: (s?: Settings): Settings | undefined => s,
668+
});
669+
`),
670+
"/home/src/workspaces/project/state.ts": stringtestutil.Dedent(`
671+
import { makeObj } from "./factory";
672+
673+
export const obj = makeObj();
674+
`),
675+
},
676+
commandLineArgs: []string{"--p", "tsconfig.json"},
677+
},
637678
{
638679
subScenario: "reports dts generation errors",
639680
files: getTscDeclarationEmitDtsErrorsFileMap(false, false),

testdata/baselines/reference/compiler/packageDeduplicationDuplicateGlobals.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22

33
=== /src/index.ts ===
44
import { useBar } from "bar";
5-
>useBar : () => ReturnType<() => typeof myGlobal>
5+
>useBar : () => ReturnType<typeof import(".pnpm/foo@1.0.0+globals@1.0.0/node_modules/foo").useFoo>
66

77
import { useBaz } from "baz";
8-
>useBaz : () => ReturnType<() => typeof myGlobal>
8+
>useBaz : () => ReturnType<typeof import(".pnpm/foo@1.0.0+globals@1.0.0/node_modules/foo").useFoo>
99

1010
const barResult = useBar();
1111
>barResult : string
1212
>useBar() : string
13-
>useBar : () => ReturnType<() => typeof myGlobal>
13+
>useBar : () => ReturnType<typeof import(".pnpm/foo@1.0.0+globals@1.0.0/node_modules/foo").useFoo>
1414

1515
const bazResult = useBaz();
1616
>bazResult : string
1717
>useBaz() : string
18-
>useBaz : () => ReturnType<() => typeof myGlobal>
18+
>useBaz : () => ReturnType<typeof import(".pnpm/foo@1.0.0+globals@1.0.0/node_modules/foo").useFoo>
1919

2020
const x: string = myGlobal;
2121
>x : string

testdata/baselines/reference/submodule/compiler/declarationEmitUsingTypeAlias2.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ export { shouldLookupName, shouldReuseLocalName, reuseDepName, shouldBeElided };
7070

7171
=== src/index.ts ===
7272
import { goodDeclaration, shouldReuseLocalName, shouldBeElided } from "some-dep";
73-
>goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
73+
>goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
7474
>shouldReuseLocalName : unique symbol
7575
>shouldBeElided : unique symbol
7676

7777
export const bar = goodDeclaration<{}>;
78-
>bar : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
79-
>goodDeclaration<{}> : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
80-
>goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
78+
>bar : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
79+
>goodDeclaration<{}> : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
80+
>goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
8181

8282

testdata/baselines/reference/submodule/compiler/declarationEmitUsingTypeAlias2.types.diff

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,4 @@
88
+>goodDeclaration : <T>() => () => { shouldPrintResult: T extends Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? Other : "N"; shouldLookupName: typeof import('./other').shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof reuseDepName; }
99

1010
/** Other Can't be named in index.ts, but the whole conditional type can be resolved */
11-
shouldPrintResult: T extends Other? "O": "N",
12-
@@= skipped -34, +34 lines =@@
13-
14-
=== src/index.ts ===
15-
import { goodDeclaration, shouldReuseLocalName, shouldBeElided } from "some-dep";
16-
->goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
17-
+>goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
18-
>shouldReuseLocalName : unique symbol
19-
>shouldBeElided : unique symbol
20-
21-
export const bar = goodDeclaration<{}>;
22-
->bar : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
23-
->goodDeclaration<{}> : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
24-
->goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: typeof import("some-dep").reuseDepName; }
25-
+>bar : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
26-
+>goodDeclaration<{}> : () => () => { shouldPrintResult: "N"; shouldPrintResult2: "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
27-
+>goodDeclaration : <T>() => () => { shouldPrintResult: T extends import("../node_modules/some-dep/dist/inner").Other ? "O" : "N"; shouldPrintResult2: T extends typeof shouldBeElided ? import("../node_modules/some-dep/dist/inner").Other : "N"; shouldLookupName: typeof import("some-dep").shouldLookupName; shouldReuseLocalName: typeof shouldReuseLocalName; reuseDepName: unique symbol; }
28-
11+
shouldPrintResult: T extends Other? "O": "N",

testdata/baselines/reference/submodule/compiler/reactTransitiveImportHasValidDeclaration.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ export default function styled(tag: string): (o: object) => StyledOtherComponent
4545

4646
=== index.ts ===
4747
import styled from "react-emotion"
48-
>styled : (tag: string) => (o: object) => import("create-emotion-styled").StyledOtherComponent<{}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, any>
48+
>styled : (tag: string) => (o: object) => import("create-emotion-styled").StyledOtherComponent<{}, import("create-emotion-styled").StyledOtherComponentList["div"], any>
4949

5050
const Form = styled('div')({ color: "red" })
5151
>Form : import("create-emotion-styled").StyledOtherComponent<{}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, any>
5252
>styled('div')({ color: "red" }) : import("create-emotion-styled").StyledOtherComponent<{}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, any>
53-
>styled('div') : (o: object) => import("create-emotion-styled").StyledOtherComponent<{}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, any>
54-
>styled : (tag: string) => (o: object) => import("create-emotion-styled").StyledOtherComponent<{}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, any>
53+
>styled('div') : (o: object) => import("create-emotion-styled").StyledOtherComponent<{}, import("create-emotion-styled").StyledOtherComponentList["div"], any>
54+
>styled : (tag: string) => (o: object) => import("create-emotion-styled").StyledOtherComponent<{}, import("create-emotion-styled").StyledOtherComponentList["div"], any>
5555
>'div' : "div"
5656
>{ color: "red" } : { color: string; }
5757
>color : string

testdata/baselines/reference/submodule/compiler/reactTransitiveImportHasValidDeclaration.types.diff

Lines changed: 0 additions & 19 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/symlinkedWorkspaceDependenciesNoDirectLinkGeneratesDeepNonrelativeName.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import * as pkg from "package-b";
2929
export const a = pkg.invoke();
3030
>a : import("package-a/cls").Foo
3131
>pkg.invoke() : import("package-a/cls").Foo
32-
>pkg.invoke : () => ReturnType<() => import("package-a/cls").Foo>
32+
>pkg.invoke : () => ReturnType<typeof import("package-a").create>
3333
>pkg : typeof pkg
34-
>invoke : () => ReturnType<() => import("package-a/cls").Foo>
34+
>invoke : () => ReturnType<typeof import("package-a").create>
3535

testdata/baselines/reference/submodule/compiler/symlinkedWorkspaceDependenciesNoDirectLinkGeneratesDeepNonrelativeName.types.diff

Lines changed: 0 additions & 11 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
currentDirectory::/home/src/workspaces/project
2+
useCaseSensitiveFileNames::true
3+
Input::
4+
//// [/home/src/tslibs/TS/Lib/lib.es2022.full.d.ts] *new*
5+
/// <reference no-default-lib="true"/>
6+
interface Boolean {}
7+
interface Function {}
8+
interface CallableFunction {}
9+
interface NewableFunction {}
10+
interface IArguments {}
11+
interface Number { toExponential: any; }
12+
interface Object {}
13+
interface RegExp {}
14+
interface String { charAt: any; }
15+
interface Array<T> { length: number; [n: number]: T; }
16+
interface ReadonlyArray<T> {}
17+
interface SymbolConstructor {
18+
(desc?: string | number): symbol;
19+
for(name: string): symbol;
20+
readonly toStringTag: symbol;
21+
}
22+
declare var Symbol: SymbolConstructor;
23+
interface Symbol {
24+
readonly [Symbol.toStringTag]: string;
25+
}
26+
declare const console: { log(msg: any): void; };
27+
type Partial<T> = {
28+
[K in keyof T]?: T[K];
29+
};
30+
//// [/home/src/workspaces/project/a.ts] *new*
31+
interface ISettings {
32+
age: number;
33+
}
34+
35+
export type Settings = Partial<ISettings>;
36+
//// [/home/src/workspaces/project/factory.ts] *new*
37+
import type { Settings } from "./a";
38+
39+
export const makeObj = () => ({
40+
fn: (s?: Settings): Settings | undefined => s,
41+
});
42+
//// [/home/src/workspaces/project/state.ts] *new*
43+
import { makeObj } from "./factory";
44+
45+
export const obj = makeObj();
46+
//// [/home/src/workspaces/project/tsconfig.json] *new*
47+
{
48+
"compilerOptions": {
49+
"strict": true,
50+
"declaration": true,
51+
"emitDeclarationOnly": true,
52+
"target": "es2022",
53+
"module": "esnext",
54+
},
55+
"files": ["./a.ts", "./factory.ts", "./state.ts"],
56+
}
57+
58+
tsgo --p tsconfig.json
59+
ExitStatus:: Success
60+
Output::
61+
//// [/home/src/workspaces/project/a.d.ts] *new*
62+
interface ISettings {
63+
age: number;
64+
}
65+
export type Settings = Partial<ISettings>;
66+
export {};
67+
68+
//// [/home/src/workspaces/project/factory.d.ts] *new*
69+
import type { Settings } from "./a";
70+
export declare const makeObj: () => {
71+
fn: (s?: Settings) => Settings | undefined;
72+
};
73+
74+
//// [/home/src/workspaces/project/state.d.ts] *new*
75+
export declare const obj: {
76+
fn: (s?: import("./a").Settings) => import("./a").Settings | undefined;
77+
};
78+
79+

0 commit comments

Comments
 (0)