From 9f332db0e8e17ff5b2657270a4d5396fcb2b91e7 Mon Sep 17 00:00:00 2001 From: orta therox Date: Fri, 24 Apr 2020 13:43:56 -0400 Subject: [PATCH 1/2] Enforce all JSDoc import references use the value of a type --- src/compiler/checker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 52a667a14514f..be8282c9aba90 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13305,7 +13305,9 @@ namespace ts { links.resolvedSymbol = unknownSymbol; return links.resolvedType = errorType; } - const targetMeaning = node.isTypeOf ? SymbolFlags.Value : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; + const targetMeaning = node.isTypeOf || isJSDocTypeExpression(node.parent) ? SymbolFlags.Value + : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type + : SymbolFlags.Type; // TODO: Future work: support unions/generics/whatever via a deferred import-type const innerModuleSymbol = resolveExternalModuleName(node, node.argument.literal); if (!innerModuleSymbol) { From 97db3b5837423606b70ad27147e94a4f5771a6a6 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 4 May 2020 15:35:20 -0400 Subject: [PATCH 2/2] Only do an extra JSDoc type reference lookup when on a class - fixes #36830 --- src/compiler/checker.ts | 15 ++++++++++----- .../jsDocImplicitTypeOfForValueImport.symbols | 15 +++++++++++++++ .../jsdocImportTypeReferenceToClassAlias.symbols | 2 -- .../jsdocImportTypeReferenceToClassAlias.types | 8 ++++---- .../compiler/jsDocImplicitTypeOfForValueImport.ts | 14 ++++++++++++++ tests/cases/fourslash/fourslash.ts | 2 +- 6 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/jsDocImplicitTypeOfForValueImport.symbols create mode 100644 tests/cases/compiler/jsDocImplicitTypeOfForValueImport.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index be8282c9aba90..578a3ffc84e49 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11616,9 +11616,16 @@ namespace ts { } isRequireAlias = isCallExpression(expr) && isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !!valueType.symbol; } - const isImportTypeWithQualifier = node.kind === SyntaxKind.ImportType && (node as ImportTypeNode).qualifier; + + // We need to do an extra hop to find the correct type when type being referred is a class, because + // a class and its type are interwoven in the type, see jsdocImportTypeReferenceToClassAlias for + // an example of it in action + const isImportOfClassTypeWithQualifier = node.kind === SyntaxKind.ImportType + && (node as ImportTypeNode).qualifier + && valueType.symbol.flags & SymbolFlags.Class; // valueType might not have a symbol, eg, {import('./b').STRING_LITERAL} - if (valueType.symbol && (isRequireAlias || isImportTypeWithQualifier)) { + if (valueType.symbol && (isRequireAlias || isImportOfClassTypeWithQualifier)) { + // follow fake alias (commonjs or class value->type) typeType = getTypeReferenceType(node, valueType.symbol); } } @@ -13305,9 +13312,7 @@ namespace ts { links.resolvedSymbol = unknownSymbol; return links.resolvedType = errorType; } - const targetMeaning = node.isTypeOf || isJSDocTypeExpression(node.parent) ? SymbolFlags.Value - : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type - : SymbolFlags.Type; + const targetMeaning = node.isTypeOf ? SymbolFlags.Value : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; // TODO: Future work: support unions/generics/whatever via a deferred import-type const innerModuleSymbol = resolveExternalModuleName(node, node.argument.literal); if (!innerModuleSymbol) { diff --git a/tests/baselines/reference/jsDocImplicitTypeOfForValueImport.symbols b/tests/baselines/reference/jsDocImplicitTypeOfForValueImport.symbols new file mode 100644 index 0000000000000..a3abf4774f1c3 --- /dev/null +++ b/tests/baselines/reference/jsDocImplicitTypeOfForValueImport.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/lib/index.js === +// 36830 +// + +/** @type {import('../folder/index').zzz} */ +export function xxx() { +>xxx : Symbol(xxx, Decl(index.js, 0, 0)) + + return null; +} + +=== tests/cases/compiler/folder/index.d.ts === +export function zzz(): string; +>zzz : Symbol(zzz, Decl(index.d.ts, 0, 0)) + diff --git a/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.symbols b/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.symbols index c62d8e0676fa5..5f08204665854 100644 --- a/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.symbols +++ b/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.symbols @@ -21,8 +21,6 @@ function demo(c) { >c : Symbol(c, Decl(test.js, 2, 14)) c.s ->c.s : Symbol(C.s, Decl(mod1.js, 0, 9)) >c : Symbol(c, Decl(test.js, 2, 14)) ->s : Symbol(C.s, Decl(mod1.js, 0, 9)) } diff --git a/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.types b/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.types index 49b85f1f06361..8edd93653be46 100644 --- a/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.types +++ b/tests/baselines/reference/jsdocImportTypeReferenceToClassAlias.types @@ -19,11 +19,11 @@ module.exports.C = C /** @param {X} c */ function demo(c) { >demo : (c: X) => void ->c : C +>c : typeof C c.s ->c.s : () => void ->c : C ->s : () => void +>c.s : any +>c : typeof C +>s : any } diff --git a/tests/cases/compiler/jsDocImplicitTypeOfForValueImport.ts b/tests/cases/compiler/jsDocImplicitTypeOfForValueImport.ts new file mode 100644 index 0000000000000..9670ec615e9e9 --- /dev/null +++ b/tests/cases/compiler/jsDocImplicitTypeOfForValueImport.ts @@ -0,0 +1,14 @@ +// 36830 +// +// @allowJs: true +// @noEmit: true +// @checkJs: true + +// @filename: lib/index.js +/** @type {import('../folder/index').zzz} */ +export function xxx() { + return null; +} + +// @filename: folder/index.d.ts +export function zzz(): string; diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index d9b47adc1fb7a..542e8e63ba00f 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -28,7 +28,7 @@ //--------------------------------------- // For API editors: -// When editting this file, and only while editing this file, enable the reference comments +// When editing this file, and only while editing this file, enable the reference comments // and comment out the declarations in this section to get proper type information. // Undo these changes before compiling/committing/editing any other fourslash tests. // The test suite will likely crash if you try 'jake runtests' with reference comments enabled.