From 4bba6ee02eff31997e72438762c42adbc7f4d59d Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 28 Sep 2017 13:43:39 -0700 Subject: [PATCH] Support accessing enum types from JSDoc (#18703) --- src/compiler/checker.ts | 57 ++++++++++--------- .../reference/jsdocAccessEnumType.symbols | 16 ++++++ .../reference/jsdocAccessEnumType.types | 16 ++++++ tests/cases/compiler/jsdocAccessEnumType.ts | 11 ++++ 4 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 tests/baselines/reference/jsdocAccessEnumType.symbols create mode 100644 tests/baselines/reference/jsdocAccessEnumType.types create mode 100644 tests/cases/compiler/jsdocAccessEnumType.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fdcac968859..541820a4110 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5252,6 +5252,10 @@ namespace ts { } function getDeclaredTypeOfSymbol(symbol: Symbol): Type { + return tryGetDeclaredTypeOfSymbol(symbol) || unknownType; + } + + function tryGetDeclaredTypeOfSymbol(symbol: Symbol): Type | undefined { if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { return getDeclaredTypeOfClassOrInterface(symbol); } @@ -5270,7 +5274,7 @@ namespace ts { if (symbol.flags & SymbolFlags.Alias) { return getDeclaredTypeOfAlias(symbol); } - return unknownType; + return undefined; } // A type reference is considered independent if each type argument is considered independent. @@ -6872,17 +6876,6 @@ namespace ts { return type; } - /** - * Get type from reference to named type that cannot be generic (enum or type parameter) - */ - function getTypeFromNonGenericTypeReference(node: TypeReferenceType, symbol: Symbol): Type { - if (node.typeArguments) { - error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol)); - return unknownType; - } - return getDeclaredTypeOfSymbol(symbol); - } - function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined { switch (node.kind) { case SyntaxKind.TypeReference: @@ -6919,24 +6912,34 @@ namespace ts { return type; } - if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) { - // A jsdoc TypeReference may have resolved to a value (as opposed to a type). If - // the symbol is a constructor function, return the inferred class type; otherwise, - // the type of this reference is just the type of the value we resolved to. - const valueType = getTypeOfSymbol(symbol); - if (valueType.symbol && !isInferredClassType(valueType)) { - const referenceType = getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments); - if (referenceType) { - return referenceType; - } + // Get type from reference to named type that cannot be generic (enum or type parameter) + const res = tryGetDeclaredTypeOfSymbol(symbol); + if (res !== undefined) { + if (typeArguments) { + error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol)); + return unknownType; } - - // Resolve the type reference as a Type for the purpose of reporting errors. - resolveTypeReferenceName(getTypeReferenceName(node), SymbolFlags.Type); - return valueType; + return res; } - return getTypeFromNonGenericTypeReference(node, symbol); + if (!(symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node))) { + return unknownType; + } + + // A jsdoc TypeReference may have resolved to a value (as opposed to a type). If + // the symbol is a constructor function, return the inferred class type; otherwise, + // the type of this reference is just the type of the value we resolved to. + const valueType = getTypeOfSymbol(symbol); + if (valueType.symbol && !isInferredClassType(valueType)) { + const referenceType = getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments); + if (referenceType) { + return referenceType; + } + } + + // Resolve the type reference as a Type for the purpose of reporting errors. + resolveTypeReferenceName(getTypeReferenceName(node), SymbolFlags.Type); + return valueType; } function getTypeReferenceTypeWorker(node: TypeReferenceType, symbol: Symbol, typeArguments: Type[]): Type | undefined { diff --git a/tests/baselines/reference/jsdocAccessEnumType.symbols b/tests/baselines/reference/jsdocAccessEnumType.symbols new file mode 100644 index 00000000000..348a3cb17d4 --- /dev/null +++ b/tests/baselines/reference/jsdocAccessEnumType.symbols @@ -0,0 +1,16 @@ +=== /a.ts === +export enum E { A } +>E : Symbol(E, Decl(a.ts, 0, 0)) +>A : Symbol(E.A, Decl(a.ts, 0, 15)) + +=== /b.js === +import { E } from "./a"; +>E : Symbol(E, Decl(b.js, 0, 8)) + +/** @type {E} */ +const e = E.A; +>e : Symbol(e, Decl(b.js, 2, 5)) +>E.A : Symbol(E.A, Decl(a.ts, 0, 15)) +>E : Symbol(E, Decl(b.js, 0, 8)) +>A : Symbol(E.A, Decl(a.ts, 0, 15)) + diff --git a/tests/baselines/reference/jsdocAccessEnumType.types b/tests/baselines/reference/jsdocAccessEnumType.types new file mode 100644 index 00000000000..a08c2b4e179 --- /dev/null +++ b/tests/baselines/reference/jsdocAccessEnumType.types @@ -0,0 +1,16 @@ +=== /a.ts === +export enum E { A } +>E : E +>A : E + +=== /b.js === +import { E } from "./a"; +>E : typeof E + +/** @type {E} */ +const e = E.A; +>e : E +>E.A : E +>E : typeof E +>A : E + diff --git a/tests/cases/compiler/jsdocAccessEnumType.ts b/tests/cases/compiler/jsdocAccessEnumType.ts new file mode 100644 index 00000000000..2676d86cc31 --- /dev/null +++ b/tests/cases/compiler/jsdocAccessEnumType.ts @@ -0,0 +1,11 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true + +// @Filename: /a.ts +export enum E { A } + +// @Filename: /b.js +import { E } from "./a"; +/** @type {E} */ +const e = E.A;