diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 072ed10aa712e..4e24f92a46b45 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5731,15 +5731,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } + function resolveTypeAliasSymbol(symbol: Symbol): Symbol | undefined { + if (!symbol.declarations) { + return; + } + for (const decl of symbol.declarations) { + if (!isTypeAliasDeclaration(decl)) { + continue; + } + const location = getDirectTypeAliasLocation(decl); + if (!location) { + continue; + } + const aliased = resolveSymbol(getSymbolAtLocation(location)); + if (aliased) { + return aliased.flags & SymbolFlags.TypeAlias && resolveTypeAliasSymbol(aliased) || aliased; + } + } + + function getDirectTypeAliasLocation(decl: TypeAliasDeclaration): Node | undefined { + if (decl.typeParameters) { + return; + } + const typeNode = decl.type; + switch (typeNode.kind) { + case SyntaxKind.TypeReference: { + const { typeName, typeArguments } = typeNode as TypeReferenceNode; + if (typeArguments) { + return; + } + return typeName; + } + case SyntaxKind.ImportType: { + const { qualifier, typeArguments } = typeNode as ImportTypeNode; + if (typeArguments) { + return; + } + return qualifier || typeNode; + } + } + } + } + /** * 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 (s1.flags & SymbolFlags.TypeAlias) { + s2 = resolveTypeAliasSymbol(s2) || s2; } - if (s2.flags & SymbolFlags.TypeAlias && s1.declarations?.find(isTypeAlias)) { - s1 = getDeclaredTypeOfTypeAlias(s1).aliasSymbol || s1; + if (s2.flags & SymbolFlags.TypeAlias) { + s1 = resolveTypeAliasSymbol(s1) || s1; } if (getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === getMergedSymbol(resolveSymbol(getMergedSymbol(s2)))) { return s1; diff --git a/tests/baselines/reference/declarationEmitUsingTypeAlias2.js b/tests/baselines/reference/declarationEmitUsingTypeAlias2.js new file mode 100644 index 0000000000000..066c7f468d7f5 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias2.js @@ -0,0 +1,53 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias2.ts] //// + +//// [inner.d.ts] +export declare type Other = { other: string }; +export declare type SomeType = { arg: Other }; + +//// [indirection.d.ts] +import { Other as IndirectOther, SomeType as IndirectSomeType } from './inner'; +export declare type Other = IndirectOther; +export declare type SomeType = IndirectSomeType + +//// [index.d.ts] +import { Other, SomeType as IndirectSomeType } from './indirection'; +export type OtherType = Other; +export type SomeType = IndirectSomeType; + +//// [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/declarationEmitUsingTypeAlias2.symbols b/tests/baselines/reference/declarationEmitUsingTypeAlias2.symbols new file mode 100644 index 0000000000000..d71dc0f0c85cc --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias2.symbols @@ -0,0 +1,66 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias2.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/indirection.d.ts === +import { Other as IndirectOther, SomeType as IndirectSomeType } from './inner'; +>Other : Symbol(IndirectOther, Decl(inner.d.ts, 0, 0)) +>IndirectOther : Symbol(IndirectOther, Decl(indirection.d.ts, 0, 8)) +>SomeType : Symbol(IndirectSomeType, Decl(inner.d.ts, 0, 46)) +>IndirectSomeType : Symbol(IndirectSomeType, Decl(indirection.d.ts, 0, 32)) + +export declare type Other = IndirectOther; +>Other : Symbol(Other, Decl(indirection.d.ts, 0, 79)) +>IndirectOther : Symbol(IndirectOther, Decl(indirection.d.ts, 0, 8)) + +export declare type SomeType = IndirectSomeType +>SomeType : Symbol(SomeType, Decl(indirection.d.ts, 1, 42)) +>IndirectSomeType : Symbol(IndirectSomeType, Decl(indirection.d.ts, 0, 32)) + +=== node_modules/some-dep/dist/index.d.ts === +import { Other, SomeType as IndirectSomeType } from './indirection'; +>Other : Symbol(Other, Decl(index.d.ts, 0, 8)) +>SomeType : Symbol(IndirectSomeType, Decl(indirection.d.ts, 1, 42)) +>IndirectSomeType : Symbol(IndirectSomeType, Decl(index.d.ts, 0, 15)) + +export type OtherType = Other; +>OtherType : Symbol(OtherType, Decl(index.d.ts, 0, 68)) +>Other : Symbol(Other, Decl(index.d.ts, 0, 8)) + +export type SomeType = IndirectSomeType; +>SomeType : Symbol(SomeType, Decl(index.d.ts, 1, 30)) +>IndirectSomeType : Symbol(IndirectSomeType, Decl(index.d.ts, 0, 15)) + +=== 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/declarationEmitUsingTypeAlias2.types b/tests/baselines/reference/declarationEmitUsingTypeAlias2.types new file mode 100644 index 0000000000000..e9ca54bf1cae7 --- /dev/null +++ b/tests/baselines/reference/declarationEmitUsingTypeAlias2.types @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/declarationEmitUsingTypeAlias2.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/indirection.d.ts === +import { Other as IndirectOther, SomeType as IndirectSomeType } from './inner'; +>Other : any +>IndirectOther : any +>SomeType : any +>IndirectSomeType : any + +export declare type Other = IndirectOther; +>Other : IndirectOther + +export declare type SomeType = IndirectSomeType +>SomeType : IndirectSomeType + +=== node_modules/some-dep/dist/index.d.ts === +import { Other, SomeType as IndirectSomeType } from './indirection'; +>Other : any +>SomeType : any +>IndirectSomeType : any + +export type OtherType = Other; +>OtherType : import("node_modules/some-dep/dist/inner").Other + +export type SomeType = IndirectSomeType; +>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/baselines/reference/errorReportNotCircular1.errors.txt b/tests/baselines/reference/errorReportNotCircular1.errors.txt new file mode 100644 index 0000000000000..db4b9f1918766 --- /dev/null +++ b/tests/baselines/reference/errorReportNotCircular1.errors.txt @@ -0,0 +1,52 @@ +data.ts(6,24): error TS2345: Argument of type '{}' is not assignable to parameter of type 'Data'. + Property 'quantity' is missing in type '{}' but required in type 'Data'. +data.ts(6,28): error TS1360: Type '{ quantity: Value; }' does not satisfy the expected type '[]'. + + +==== data.ts (2 errors) ==== + // https://github.com/microsoft/TypeScript/issues/57357 + + import type { Data } from "./processor"; + + export function getData() { + return constructData({}) satisfies []; // error + ~~ +!!! error TS2345: Argument of type '{}' is not assignable to parameter of type 'Data'. +!!! error TS2345: Property 'quantity' is missing in type '{}' but required in type 'Data'. +!!! related TS2728 processor.ts:6:3: 'quantity' is declared here. + ~~~~~~~~~ +!!! error TS1360: Type '{ quantity: Value; }' does not satisfy the expected type '[]'. + } + + function constructData(data: Data) { + const { ...props } = data; + return { + ...props, + }; + } + +==== type.ts (0 errors) ==== + export type Value = {}; + +==== processor.ts (0 errors) ==== + import { getData } from "./data"; + + import type { Value } from "./type"; + + export type Data = { + quantity: Value; + }; + + declare function createRequestProcessor(pipeline: () => Req): Req; + + export const processor = createRequestProcessor(getData); + +==== main.ts (0 errors) ==== + import { processor } from "./processor"; + export default processor; + +==== workerinterface.ts (0 errors) ==== + import type Server from "./main"; + + export type _T = typeof Server; + \ No newline at end of file diff --git a/tests/baselines/reference/errorReportNotCircular1.js b/tests/baselines/reference/errorReportNotCircular1.js new file mode 100644 index 0000000000000..3ce34276d810d --- /dev/null +++ b/tests/baselines/reference/errorReportNotCircular1.js @@ -0,0 +1,65 @@ +//// [tests/cases/compiler/errorReportNotCircular1.ts] //// + +//// [data.ts] +// https://github.com/microsoft/TypeScript/issues/57357 + +import type { Data } from "./processor"; + +export function getData() { + return constructData({}) satisfies []; // error +} + +function constructData(data: Data) { + const { ...props } = data; + return { + ...props, + }; +} + +//// [type.ts] +export type Value = {}; + +//// [processor.ts] +import { getData } from "./data"; + +import type { Value } from "./type"; + +export type Data = { + quantity: Value; +}; + +declare function createRequestProcessor(pipeline: () => Req): Req; + +export const processor = createRequestProcessor(getData); + +//// [main.ts] +import { processor } from "./processor"; +export default processor; + +//// [workerinterface.ts] +import type Server from "./main"; + +export type _T = typeof Server; + + +//// [type.js] +export {}; +//// [processor.js] +import { getData } from "./data"; +export const processor = createRequestProcessor(getData); +//// [data.js] +// https://github.com/microsoft/TypeScript/issues/57357 +export function getData() { + return constructData({}); // error +} +function constructData(data) { + const { ...props } = data; + return { + ...props, + }; +} +//// [main.js] +import { processor } from "./processor"; +export default processor; +//// [workerinterface.js] +export {}; diff --git a/tests/baselines/reference/errorReportNotCircular1.symbols b/tests/baselines/reference/errorReportNotCircular1.symbols new file mode 100644 index 0000000000000..e55befd3e9046 --- /dev/null +++ b/tests/baselines/reference/errorReportNotCircular1.symbols @@ -0,0 +1,78 @@ +//// [tests/cases/compiler/errorReportNotCircular1.ts] //// + +=== data.ts === +// https://github.com/microsoft/TypeScript/issues/57357 + +import type { Data } from "./processor"; +>Data : Symbol(Data, Decl(data.ts, 2, 13)) + +export function getData() { +>getData : Symbol(getData, Decl(data.ts, 2, 40)) + + return constructData({}) satisfies []; // error +>constructData : Symbol(constructData, Decl(data.ts, 6, 1)) +} + +function constructData(data: Data) { +>constructData : Symbol(constructData, Decl(data.ts, 6, 1)) +>data : Symbol(data, Decl(data.ts, 8, 23)) +>Data : Symbol(Data, Decl(data.ts, 2, 13)) + + const { ...props } = data; +>props : Symbol(props, Decl(data.ts, 9, 9)) +>data : Symbol(data, Decl(data.ts, 8, 23)) + + return { + ...props, +>props : Symbol(props, Decl(data.ts, 9, 9)) + + }; +} + +=== type.ts === +export type Value = {}; +>Value : Symbol(Value, Decl(type.ts, 0, 0)) + +=== processor.ts === +import { getData } from "./data"; +>getData : Symbol(getData, Decl(processor.ts, 0, 8)) + +import type { Value } from "./type"; +>Value : Symbol(Value, Decl(processor.ts, 2, 13)) + +export type Data = { +>Data : Symbol(Data, Decl(processor.ts, 2, 36)) + + quantity: Value; +>quantity : Symbol(quantity, Decl(processor.ts, 4, 20)) +>Value : Symbol(Value, Decl(processor.ts, 2, 13)) + +}; + +declare function createRequestProcessor(pipeline: () => Req): Req; +>createRequestProcessor : Symbol(createRequestProcessor, Decl(processor.ts, 6, 2)) +>Req : Symbol(Req, Decl(processor.ts, 8, 40)) +>pipeline : Symbol(pipeline, Decl(processor.ts, 8, 45)) +>Req : Symbol(Req, Decl(processor.ts, 8, 40)) +>Req : Symbol(Req, Decl(processor.ts, 8, 40)) + +export const processor = createRequestProcessor(getData); +>processor : Symbol(processor, Decl(processor.ts, 10, 12)) +>createRequestProcessor : Symbol(createRequestProcessor, Decl(processor.ts, 6, 2)) +>getData : Symbol(getData, Decl(processor.ts, 0, 8)) + +=== main.ts === +import { processor } from "./processor"; +>processor : Symbol(processor, Decl(main.ts, 0, 8)) + +export default processor; +>processor : Symbol(processor, Decl(main.ts, 0, 8)) + +=== workerinterface.ts === +import type Server from "./main"; +>Server : Symbol(Server, Decl(workerinterface.ts, 0, 6)) + +export type _T = typeof Server; +>_T : Symbol(_T, Decl(workerinterface.ts, 0, 33)) +>Server : Symbol(Server, Decl(workerinterface.ts, 0, 6)) + diff --git a/tests/baselines/reference/errorReportNotCircular1.types b/tests/baselines/reference/errorReportNotCircular1.types new file mode 100644 index 0000000000000..bb8f156b932b1 --- /dev/null +++ b/tests/baselines/reference/errorReportNotCircular1.types @@ -0,0 +1,79 @@ +//// [tests/cases/compiler/errorReportNotCircular1.ts] //// + +=== data.ts === +// https://github.com/microsoft/TypeScript/issues/57357 + +import type { Data } from "./processor"; +>Data : Data + +export function getData() { +>getData : () => { quantity: import("type").Value; } + + return constructData({}) satisfies []; // error +>constructData({}) satisfies [] : { quantity: import("type").Value; } +>constructData({}) : { quantity: import("type").Value; } +>constructData : (data: Data) => { quantity: import("type").Value; } +>{} : {} +} + +function constructData(data: Data) { +>constructData : (data: Data) => { quantity: import("type").Value; } +>data : Data + + const { ...props } = data; +>props : { quantity: import("type").Value; } +>data : Data + + return { +>{ ...props, } : { quantity: import("type").Value; } + + ...props, +>props : { quantity: import("type").Value; } + + }; +} + +=== type.ts === +export type Value = {}; +>Value : {} + +=== processor.ts === +import { getData } from "./data"; +>getData : () => { quantity: Value; } + +import type { Value } from "./type"; +>Value : Value + +export type Data = { +>Data : { quantity: Value; } + + quantity: Value; +>quantity : Value + +}; + +declare function createRequestProcessor(pipeline: () => Req): Req; +>createRequestProcessor : (pipeline: () => Req) => Req +>pipeline : () => Req + +export const processor = createRequestProcessor(getData); +>processor : { quantity: Value; } +>createRequestProcessor(getData) : { quantity: Value; } +>createRequestProcessor : (pipeline: () => Req) => Req +>getData : () => { quantity: Value; } + +=== main.ts === +import { processor } from "./processor"; +>processor : { quantity: import("type").Value; } + +export default processor; +>processor : { quantity: import("type").Value; } + +=== workerinterface.ts === +import type Server from "./main"; +>Server : any + +export type _T = typeof Server; +>_T : { quantity: import("type").Value; } +>Server : { quantity: import("type").Value; } + diff --git a/tests/cases/compiler/declarationEmitUsingTypeAlias2.ts b/tests/cases/compiler/declarationEmitUsingTypeAlias2.ts new file mode 100644 index 0000000000000..a798ff0e39c92 --- /dev/null +++ b/tests/cases/compiler/declarationEmitUsingTypeAlias2.ts @@ -0,0 +1,36 @@ +// @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/indirection.d.ts +import { Other as IndirectOther, SomeType as IndirectSomeType } from './inner'; +export declare type Other = IndirectOther; +export declare type SomeType = IndirectSomeType + +// @filename: node_modules/some-dep/dist/index.d.ts +import { Other, SomeType as IndirectSomeType } from './indirection'; +export type OtherType = Other; +export type SomeType = IndirectSomeType; + +// @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 diff --git a/tests/cases/compiler/errorReportNotCircular1.ts b/tests/cases/compiler/errorReportNotCircular1.ts new file mode 100644 index 0000000000000..bec483a45288d --- /dev/null +++ b/tests/cases/compiler/errorReportNotCircular1.ts @@ -0,0 +1,43 @@ +// @strict: true +// @target: esnext + +// https://github.com/microsoft/TypeScript/issues/57357 + +// @filename: data.ts +import type { Data } from "./processor"; + +export function getData() { + return constructData({}) satisfies []; // error +} + +function constructData(data: Data) { + const { ...props } = data; + return { + ...props, + }; +} + +// @filename: type.ts +export type Value = {}; + +// @filename: processor.ts +import { getData } from "./data"; + +import type { Value } from "./type"; + +export type Data = { + quantity: Value; +}; + +declare function createRequestProcessor(pipeline: () => Req): Req; + +export const processor = createRequestProcessor(getData); + +// @filename: main.ts +import { processor } from "./processor"; +export default processor; + +// @filename: workerinterface.ts +import type Server from "./main"; + +export type _T = typeof Server;