From bcef7eba53e61bbde4b91dad9886aed2ff928f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=BChle?= Date: Mon, 5 Feb 2024 22:40:50 +0100 Subject: [PATCH] Always emit `Object` type in decorator metadata for import type (#56594) --- src/compiler/checker.ts | 21 ++++++---- ...decoratorMetadataTypeOnlyImport.errors.txt | 18 +++++++++ .../decoratorMetadataTypeOnlyImport.js | 40 +++++++++++++++++++ .../decoratorMetadataTypeOnlyImport.symbols | 26 ++++++++++++ .../decoratorMetadataTypeOnlyImport.types | 24 +++++++++++ .../decoratorMetadataTypeOnlyImport.ts | 15 +++++++ 6 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/decoratorMetadataTypeOnlyImport.errors.txt create mode 100644 tests/baselines/reference/decoratorMetadataTypeOnlyImport.js create mode 100644 tests/baselines/reference/decoratorMetadataTypeOnlyImport.symbols create mode 100644 tests/baselines/reference/decoratorMetadataTypeOnlyImport.types create mode 100644 tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f15fd70378e..91a5c09454b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -48312,28 +48312,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isTypeOnly = !!rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); } const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; + const resolvedValueSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; isTypeOnly ||= !!(valueSymbol && getTypeOnlyAliasDeclaration(valueSymbol, SymbolFlags.Value)); // Resolve the symbol as a type so that we can provide a more useful hint for the type serializer. - const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location); - if (resolvedSymbol && resolvedSymbol === typeSymbol) { + const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); + const resolvedTypeSymbol = typeSymbol && typeSymbol.flags & SymbolFlags.Alias ? resolveAlias(typeSymbol) : typeSymbol; + + // In case the value symbol can't be resolved (e.g. because of missing declarations), use type symbol for reachability check. + if (!valueSymbol) { + isTypeOnly ||= !!(typeSymbol && getTypeOnlyAliasDeclaration(typeSymbol, SymbolFlags.Type)); + } + + if (resolvedValueSymbol && resolvedValueSymbol === resolvedTypeSymbol) { const globalPromiseSymbol = getGlobalPromiseConstructorSymbol(/*reportErrors*/ false); - if (globalPromiseSymbol && resolvedSymbol === globalPromiseSymbol) { + if (globalPromiseSymbol && resolvedValueSymbol === globalPromiseSymbol) { return TypeReferenceSerializationKind.Promise; } - const constructorType = getTypeOfSymbol(resolvedSymbol); + const constructorType = getTypeOfSymbol(resolvedValueSymbol); if (constructorType && isConstructorType(constructorType)) { return isTypeOnly ? TypeReferenceSerializationKind.TypeWithCallSignature : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; } } // We might not be able to resolve type symbol so use unknown type in that case (eg error case) - if (!typeSymbol) { + if (!resolvedTypeSymbol) { return isTypeOnly ? TypeReferenceSerializationKind.ObjectType : TypeReferenceSerializationKind.Unknown; } - const type = getDeclaredTypeOfSymbol(typeSymbol); + const type = getDeclaredTypeOfSymbol(resolvedTypeSymbol); if (isErrorType(type)) { return isTypeOnly ? TypeReferenceSerializationKind.ObjectType : TypeReferenceSerializationKind.Unknown; } diff --git a/tests/baselines/reference/decoratorMetadataTypeOnlyImport.errors.txt b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.errors.txt new file mode 100644 index 00000000000..0970fe9461e --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.errors.txt @@ -0,0 +1,18 @@ +a.ts(1,22): error TS2307: Cannot find module 'unknown-module' or its corresponding type declarations. + + +==== ./a.ts (1 errors) ==== + import { List } from 'unknown-module'; + ~~~~~~~~~~~~~~~~ +!!! error TS2307: Cannot find module 'unknown-module' or its corresponding type declarations. + export type MyList = List; + +==== ./b.ts (0 errors) ==== + import { type MyList } from './a'; + + declare var Decorator: any; + + class Foo { + @Decorator myList?: MyList; + } + \ No newline at end of file diff --git a/tests/baselines/reference/decoratorMetadataTypeOnlyImport.js b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.js new file mode 100644 index 00000000000..3b6bf1c96c1 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.js @@ -0,0 +1,40 @@ +//// [tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts] //// + +//// [a.ts] +import { List } from 'unknown-module'; +export type MyList = List; + +//// [b.ts] +import { type MyList } from './a'; + +declare var Decorator: any; + +class Foo { + @Decorator myList?: MyList; +} + + +//// [a.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//// [b.js] +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var Foo = /** @class */ (function () { + function Foo() { + } + __decorate([ + Decorator, + __metadata("design:type", Object) + ], Foo.prototype, "myList", void 0); + return Foo; +}()); diff --git a/tests/baselines/reference/decoratorMetadataTypeOnlyImport.symbols b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.symbols new file mode 100644 index 00000000000..478cff505e5 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.symbols @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts] //// + +=== ./a.ts === +import { List } from 'unknown-module'; +>List : Symbol(List, Decl(a.ts, 0, 8)) + +export type MyList = List; +>MyList : Symbol(MyList, Decl(a.ts, 0, 38)) +>List : Symbol(List, Decl(a.ts, 0, 8)) + +=== ./b.ts === +import { type MyList } from './a'; +>MyList : Symbol(MyList, Decl(b.ts, 0, 8)) + +declare var Decorator: any; +>Decorator : Symbol(Decorator, Decl(b.ts, 2, 11)) + +class Foo { +>Foo : Symbol(Foo, Decl(b.ts, 2, 27)) + + @Decorator myList?: MyList; +>Decorator : Symbol(Decorator, Decl(b.ts, 2, 11)) +>myList : Symbol(Foo.myList, Decl(b.ts, 4, 11)) +>MyList : Symbol(MyList, Decl(b.ts, 0, 8)) +} + diff --git a/tests/baselines/reference/decoratorMetadataTypeOnlyImport.types b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.types new file mode 100644 index 00000000000..86fd09312f7 --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataTypeOnlyImport.types @@ -0,0 +1,24 @@ +//// [tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts] //// + +=== ./a.ts === +import { List } from 'unknown-module'; +>List : any + +export type MyList = List; +>MyList : List + +=== ./b.ts === +import { type MyList } from './a'; +>MyList : any + +declare var Decorator: any; +>Decorator : any + +class Foo { +>Foo : Foo + + @Decorator myList?: MyList; +>Decorator : any +>myList : List +} + diff --git a/tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts b/tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts new file mode 100644 index 00000000000..fda2124e2ed --- /dev/null +++ b/tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts @@ -0,0 +1,15 @@ +// @experimentalDecorators: true +// @emitDecoratorMetadata: true + +// @filename: ./a.ts +import { List } from 'unknown-module'; +export type MyList = List; + +// @filename: ./b.ts +import { type MyList } from './a'; + +declare var Decorator: any; + +class Foo { + @Decorator myList?: MyList; +}