From d2c0ec754bdbbb75e4bc57be17f708d5200b4cb9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 21 Nov 2017 10:17:48 -0800 Subject: [PATCH] JS:resolve nested static classes+on func/class exps 1. In Javascript, support type references to class expressions whose name is obtained via "static property assignment" to another class like so: ```ts function Outer() { this.y = 2 } Outer.Inner = class { } /** @type {Outer.Inner} */ var inner; ``` 2. In Javascript, support type references to properties of function and class expressions that are assigned to a variable, like so: ```ts var Outer = function { this.y = 2 } Outer.Inner = class { } /** @type {Outer.Inner} */ var inner; ``` --- src/compiler/checker.ts | 13 ++++++++++++- src/compiler/utilities.ts | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cde61bb4071..2ad014aaabc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1733,13 +1733,24 @@ namespace ts { return undefined; } const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name; - const namespace = resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors, /*dontResolveAlias*/ false, location); + let namespace = resolveEntityName(left, SymbolFlags.Namespace, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location); + if (!namespace && name.parent && isJSDocTypeReference(name.parent as TypeReferenceType)) { + // jsdoc type references may be values + namespace = resolveEntityName(left, SymbolFlags.Value, ignoreErrors, /*dontResolveAlias*/ false, location); + } + else if (!ignoreErrors) { + // run again for error reporting purposes + resolveEntityName(left, SymbolFlags.Namespace, /*ignoreErrors*/ false, /*dontResolveAlias*/ false, location); + } if (!namespace || nodeIsMissing(right)) { return undefined; } else if (namespace === unknownSymbol) { return namespace; } + if (isInJavaScriptFile(name) && isDeclarationOfFunctionOrClassExpression(namespace)) { + namespace = getSymbolOfNode((namespace.valueDeclaration as VariableDeclaration).initializer); + } symbol = getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning); if (!symbol) { if (!ignoreErrors) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4bc519c2b8e..a08990e4c43 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1435,7 +1435,7 @@ namespace ts { } /** - * Returns true if the node is a variable declaration whose initializer is a function expression. + * Returns true if the node is a variable declaration whose initializer is a function or class expression. * This function does not test if the node is in a JavaScript file or not. */ export function isDeclarationOfFunctionOrClassExpression(s: Symbol) {