Always emit Object type in decorator metadata for import type (#56594)

This commit is contained in:
Jan Kühle 2024-02-05 22:40:50 +01:00 committed by GitHub
parent 2514a64bdb
commit bcef7eba53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 137 additions and 7 deletions

View File

@ -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;
}

View File

@ -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<number>;
==== ./b.ts (0 errors) ====
import { type MyList } from './a';
declare var Decorator: any;
class Foo {
@Decorator myList?: MyList;
}

View File

@ -0,0 +1,40 @@
//// [tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts] ////
//// [a.ts]
import { List } from 'unknown-module';
export type MyList = List<number>;
//// [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;
}());

View File

@ -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<number>;
>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))
}

View File

@ -0,0 +1,24 @@
//// [tests/cases/compiler/decoratorMetadataTypeOnlyImport.ts] ////
=== ./a.ts ===
import { List } from 'unknown-module';
>List : any
export type MyList = List<number>;
>MyList : List<number>
=== ./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<number>
}

View File

@ -0,0 +1,15 @@
// @experimentalDecorators: true
// @emitDecoratorMetadata: true
// @filename: ./a.ts
import { List } from 'unknown-module';
export type MyList = List<number>;
// @filename: ./b.ts
import { type MyList } from './a';
declare var Decorator: any;
class Foo {
@Decorator myList?: MyList;
}