From 0068b3708dc4212ed07d28b1dd4ba24a3c463928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 12 Oct 2023 20:50:13 +0200 Subject: [PATCH 1/3] Use symbols of type aliases when emitting declarations --- src/compiler/checker.ts | 6 +++ .../declarationEmitUsingTypeAlias1.js | 47 +++++++++++++++++++ .../declarationEmitUsingTypeAlias1.symbols | 46 ++++++++++++++++++ .../declarationEmitUsingTypeAlias1.types | 43 +++++++++++++++++ .../declarationEmitUsingTypeAlias1.ts | 30 ++++++++++++ 5 files changed, 172 insertions(+) create mode 100644 tests/baselines/reference/declarationEmitUsingTypeAlias1.js create mode 100644 tests/baselines/reference/declarationEmitUsingTypeAlias1.symbols create mode 100644 tests/baselines/reference/declarationEmitUsingTypeAlias1.types create mode 100644 tests/cases/compiler/declarationEmitUsingTypeAlias1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ed6f52c38c71..c835d81482365 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5665,6 +5665,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getSymbolIfSameReference(exported, symbol)) { return exported; } + if (symbol.flags & SymbolFlags.TypeAlias) { + const aliasSymbol = getDeclaredTypeOfTypeAlias(exported).aliasSymbol; + if (aliasSymbol && getSymbolIfSameReference(aliasSymbol, symbol)) { + return exported; + } + } }); } diff --git a/tests/baselines/reference/declarationEmitUsingTypeAlias1.js b/tests/baselines/reference/declarationEmitUsingTypeAlias1.js new file mode 100644 index 0000000000000..9bfe2999627b9 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias1.js @@ -0,0 +1,47 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias1.ts] //// + +//// [inner.d.ts] +export declare type Other = { other: string }; +export declare type SomeType = { arg: Other }; + +//// [index.d.ts] +export type OtherType = import('./inner').Other; +export type SomeType = import('./inner').SomeType; + +//// [package.json] +{ + "name": "some-dep", + "exports": { + ".": "./dist/index.js" + } +} + +//// [index.ts] +import { SomeType } from "some-dep"; + +export const foo = (thing: SomeType) => { + return thing; +}; + +export const bar = (thing: SomeType) => { + return thing.arg; +}; + +//// [index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.bar = exports.foo = void 0; +var foo = function (thing) { + return thing; +}; +exports.foo = foo; +var bar = function (thing) { + return thing.arg; +}; +exports.bar = bar; + + +//// [index.d.ts] +import { SomeType } from "some-dep"; +export declare const foo: (thing: SomeType) => import("some-dep").SomeType; +export declare const bar: (thing: SomeType) => import("some-dep").OtherType; diff --git a/tests/baselines/reference/declarationEmitUsingTypeAlias1.symbols b/tests/baselines/reference/declarationEmitUsingTypeAlias1.symbols new file mode 100644 index 0000000000000..55573f5c9aff2 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias1.symbols @@ -0,0 +1,46 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias1.ts] //// + +=== node_modules/some-dep/dist/inner.d.ts === +export declare type Other = { other: string }; +>Other : Symbol(Other, Decl(inner.d.ts, 0, 0)) +>other : Symbol(other, Decl(inner.d.ts, 0, 29)) + +export declare type SomeType = { arg: Other }; +>SomeType : Symbol(SomeType, Decl(inner.d.ts, 0, 46)) +>arg : Symbol(arg, Decl(inner.d.ts, 1, 32)) +>Other : Symbol(Other, Decl(inner.d.ts, 0, 0)) + +=== node_modules/some-dep/dist/index.d.ts === +export type OtherType = import('./inner').Other; +>OtherType : Symbol(OtherType, Decl(index.d.ts, 0, 0)) +>Other : Symbol(Other, Decl(inner.d.ts, 0, 0)) + +export type SomeType = import('./inner').SomeType; +>SomeType : Symbol(SomeType, Decl(index.d.ts, 0, 48)) +>SomeType : Symbol(SomeType, Decl(inner.d.ts, 0, 46)) + +=== src/index.ts === +import { SomeType } from "some-dep"; +>SomeType : Symbol(SomeType, Decl(index.ts, 0, 8)) + +export const foo = (thing: SomeType) => { +>foo : Symbol(foo, Decl(index.ts, 2, 12)) +>thing : Symbol(thing, Decl(index.ts, 2, 20)) +>SomeType : Symbol(SomeType, Decl(index.ts, 0, 8)) + + return thing; +>thing : Symbol(thing, Decl(index.ts, 2, 20)) + +}; + +export const bar = (thing: SomeType) => { +>bar : Symbol(bar, Decl(index.ts, 6, 12)) +>thing : Symbol(thing, Decl(index.ts, 6, 20)) +>SomeType : Symbol(SomeType, Decl(index.ts, 0, 8)) + + return thing.arg; +>thing.arg : Symbol(arg, Decl(inner.d.ts, 1, 32)) +>thing : Symbol(thing, Decl(index.ts, 6, 20)) +>arg : Symbol(arg, Decl(inner.d.ts, 1, 32)) + +}; diff --git a/tests/baselines/reference/declarationEmitUsingTypeAlias1.types b/tests/baselines/reference/declarationEmitUsingTypeAlias1.types new file mode 100644 index 0000000000000..f32f9775eea30 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias1.types @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias1.ts] //// + +=== node_modules/some-dep/dist/inner.d.ts === +export declare type Other = { other: string }; +>Other : { other: string; } +>other : string + +export declare type SomeType = { arg: Other }; +>SomeType : { arg: Other; } +>arg : Other + +=== node_modules/some-dep/dist/index.d.ts === +export type OtherType = import('./inner').Other; +>OtherType : import("node_modules/some-dep/dist/inner").Other + +export type SomeType = import('./inner').SomeType; +>SomeType : import("node_modules/some-dep/dist/inner").SomeType + +=== src/index.ts === +import { SomeType } from "some-dep"; +>SomeType : any + +export const foo = (thing: SomeType) => { +>foo : (thing: SomeType) => import("node_modules/some-dep/dist/inner").SomeType +>(thing: SomeType) => { return thing;} : (thing: SomeType) => import("node_modules/some-dep/dist/inner").SomeType +>thing : import("node_modules/some-dep/dist/inner").SomeType + + return thing; +>thing : import("node_modules/some-dep/dist/inner").SomeType + +}; + +export const bar = (thing: SomeType) => { +>bar : (thing: SomeType) => import("node_modules/some-dep/dist/inner").Other +>(thing: SomeType) => { return thing.arg;} : (thing: SomeType) => import("node_modules/some-dep/dist/inner").Other +>thing : import("node_modules/some-dep/dist/inner").SomeType + + return thing.arg; +>thing.arg : import("node_modules/some-dep/dist/inner").Other +>thing : import("node_modules/some-dep/dist/inner").SomeType +>arg : import("node_modules/some-dep/dist/inner").Other + +}; diff --git a/tests/cases/compiler/declarationEmitUsingTypeAlias1.ts b/tests/cases/compiler/declarationEmitUsingTypeAlias1.ts new file mode 100644 index 0000000000000..257a82e3e32bc --- /dev/null +++ b/tests/cases/compiler/declarationEmitUsingTypeAlias1.ts @@ -0,0 +1,30 @@ +// @strict: true +// @declaration: true +// @module: nodenext + +// @filename: node_modules/some-dep/dist/inner.d.ts +export declare type Other = { other: string }; +export declare type SomeType = { arg: Other }; + +// @filename: node_modules/some-dep/dist/index.d.ts +export type OtherType = import('./inner').Other; +export type SomeType = import('./inner').SomeType; + +// @filename: node_modules/some-dep/package.json +{ + "name": "some-dep", + "exports": { + ".": "./dist/index.js" + } +} + +// @filename: src/index.ts +import { SomeType } from "some-dep"; + +export const foo = (thing: SomeType) => { + return thing; +}; + +export const bar = (thing: SomeType) => { + return thing.arg; +}; \ No newline at end of file From 672e79731e5c38eabaaeabb64be2a047e7883feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 12 Oct 2023 21:47:27 +0200 Subject: [PATCH 2/3] fixed crash --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c835d81482365..0bdec5d0cda41 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5665,7 +5665,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getSymbolIfSameReference(exported, symbol)) { return exported; } - if (symbol.flags & SymbolFlags.TypeAlias) { + if (symbol.flags & SymbolFlags.TypeAlias && exported.declarations?.find(isTypeAlias)) { const aliasSymbol = getDeclaredTypeOfTypeAlias(exported).aliasSymbol; if (aliasSymbol && getSymbolIfSameReference(aliasSymbol, symbol)) { return exported; From 862603b8ca258863775d0ac0031e3250756b2f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 7 Nov 2023 09:35:26 +0100 Subject: [PATCH 3/3] Move the fix to `getSymbolIfSameReference` itself --- src/compiler/checker.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0bdec5d0cda41..4264a41de7bdc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5665,12 +5665,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getSymbolIfSameReference(exported, symbol)) { return exported; } - if (symbol.flags & SymbolFlags.TypeAlias && exported.declarations?.find(isTypeAlias)) { - const aliasSymbol = getDeclaredTypeOfTypeAlias(exported).aliasSymbol; - if (aliasSymbol && getSymbolIfSameReference(aliasSymbol, symbol)) { - return exported; - } - } }); } @@ -5678,6 +5672,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Checks if two symbols, through aliasing and/or merging, refer to the same thing */ function getSymbolIfSameReference(s1: Symbol, s2: Symbol) { + if (s1.flags & SymbolFlags.TypeAlias && s2.declarations?.find(isTypeAlias)) { + s2 = getDeclaredTypeOfTypeAlias(s2).aliasSymbol || s2; + } + if (s2.flags & SymbolFlags.TypeAlias && s1.declarations?.find(isTypeAlias)) { + s1 = getDeclaredTypeOfTypeAlias(s1).aliasSymbol || s1; + } if (getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === getMergedSymbol(resolveSymbol(getMergedSymbol(s2)))) { return s1; }