Fix nested js-containers+proto assignment in types space

1. The actual symbols needed to be marked as containers.
2. Type node resolution needed to understand prototype assignments.
This commit is contained in:
Nathan Shively-Sanders
2018-02-23 09:16:01 -08:00
parent aa88f71c2e
commit dd2523650e
16 changed files with 471 additions and 86 deletions
+5 -2
View File
@@ -2393,7 +2393,8 @@ namespace ts {
function bindSpecialPropertyAssignment(node: BinaryExpression) {
const lhs = node.left as PropertyAccessEntityNameExpression;
// Fix up parent pointers since we're going to use these nodes before we bind into them
lhs.parent = node;
node.left.parent = node;
node.right.parent = node;
if (isIdentifier(lhs.expression) && container === file && isNameOfExportsOrModuleExportsAliasDeclaration(file, lhs.expression)) {
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
// var util = module.exports;
@@ -2444,7 +2445,9 @@ namespace ts {
(symbol.exports || (symbol.exports = createSymbolTable()));
// Declare the method/property
declareSymbol(symbolTable, symbol, propertyAccess, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
const symbolFlags = SymbolFlags.Property | (isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
const symbolExcludes = SymbolFlags.PropertyExcludes & ~(isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
declareSymbol(symbolTable, symbol, propertyAccess, symbolFlags, symbolExcludes);
}
function lookupSymbolForPropertyAccess(node: EntityNameExpression): Symbol | undefined {
+20 -33
View File
@@ -2002,21 +2002,7 @@ namespace ts {
}
}
else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) {
let left: EntityNameOrEntityNameExpression;
if (name.kind === SyntaxKind.QualifiedName) {
left = name.left;
}
else if (name.kind === SyntaxKind.PropertyAccessExpression) {
left = name.expression;
}
else {
// If the expression in property-access expression is not entity-name or parenthsizedExpression (e.g. it is a call expression), it won't be able to successfully resolve the name.
// This is the case when we are trying to do any language service operation in heritage clauses. By return undefined, the getSymbolOfEntityNameOrPropertyAccessExpression
// will attempt to checkPropertyAccessExpression to resolve symbol.
// i.e class C extends foo()./*do language service operation here*/B {}
return undefined;
}
const left = name.kind === SyntaxKind.QualifiedName ? name.left : name.expression;
const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name;
let namespace = resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors, /*dontResolveAlias*/ false, location);
if (!namespace || nodeIsMissing(right)) {
@@ -2025,8 +2011,11 @@ namespace ts {
else if (namespace === unknownSymbol) {
return namespace;
}
if (isInJavaScriptFile(name) && isDeclarationOfFunctionOrClassExpression(namespace)) {
namespace = getSymbolOfNode((namespace.valueDeclaration as VariableDeclaration).initializer);
if (isInJavaScriptFile(name)) {
const initializer = getDeclaredJavascriptInitializer(namespace.valueDeclaration);
if (initializer) {
namespace = getSymbolOfNode(initializer);
}
}
symbol = getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning);
if (!symbol) {
@@ -7246,12 +7235,11 @@ namespace ts {
// 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 assignedType = getAssignedClassType(symbol);
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType)) {
const referenceType = getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
if (referenceType) {
return referenceType;
}
const referenceType = valueType.symbol && !isInferredClassType(valueType) && getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
if (referenceType || assignedType) {
return referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType;
}
// Resolve the type reference as a Type for the purpose of reporting errors.
@@ -17894,23 +17882,22 @@ namespace ts {
}
function getJavaScriptClassType(symbol: Symbol): Type | undefined {
if (isDeclarationOfFunctionOrClassExpression(symbol)) {
symbol = getSymbolOfNode((symbol.valueDeclaration as VariableDeclaration).initializer);
const initializer = getDeclaredJavascriptInitializer(symbol.valueDeclaration);
if (initializer) {
symbol = getSymbolOfNode(initializer);
}
let assigned = getAssignedClassType(symbol);
let inferred: Type | undefined;
if (isJavaScriptConstructor(symbol.valueDeclaration)) {
inferred = getInferredClassType(symbol);
}
if (symbol.flags & SymbolFlags.Variable) {
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType) && isJavaScriptConstructor(valueType.symbol.valueDeclaration)) {
inferred = getInferredClassType(valueType.symbol);
}
const assigned = getAssignedClassType(symbol);
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType) && isJavaScriptConstructor(valueType.symbol.valueDeclaration)) {
inferred = getInferredClassType(valueType.symbol);
}
return !inferred ? assigned :
!assigned ? inferred :
getIntersectionType([inferred, assigned]);
return assigned && inferred ?
getIntersectionType([inferred, assigned]) :
assigned || inferred;
}
function getAssignedClassType(symbol: Symbol) {
+2 -2
View File
@@ -3243,8 +3243,8 @@ namespace ts {
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias | JSContainer,
Namespace = ValueModule | NamespaceModule | Enum,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
-12
View File
@@ -1471,18 +1471,6 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
}
/**
* 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) {
if (s.valueDeclaration && isVariableDeclaration(s.valueDeclaration)) {
return s.valueDeclaration.initializer &&
(s.valueDeclaration.initializer.kind === SyntaxKind.FunctionExpression || s.valueDeclaration.initializer.kind === SyntaxKind.ClassExpression);
}
return false;
}
export function getJSInitializerSymbol(symbol: Symbol) {
if (!symbol || !symbol.valueDeclaration) {
return symbol;
@@ -16,8 +16,9 @@ namespace ts.refactor.convertFunctionToES6Class {
return undefined;
}
if (isDeclarationOfFunctionOrClassExpression(symbol)) {
symbol = (symbol.valueDeclaration as VariableDeclaration).initializer.symbol;
const initializer = getDeclaredJavascriptInitializer(symbol.valueDeclaration);
if (initializer) {
symbol = initializer.symbol;
}
if ((symbol.flags & SymbolFlags.Function) && symbol.members && (symbol.members.size > 0)) {
@@ -264,4 +265,4 @@ namespace ts.refactor.convertFunctionToES6Class {
const token = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false);
return checker.getSymbolAtLocation(token);
}
}
}
+17 -17
View File
@@ -1956,28 +1956,28 @@ declare namespace ts {
JSContainer = 67108864,
Enum = 384,
Variable = 3,
Value = 107455,
Type = 793064,
Value = 67216319,
Type = 67901928,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 107454,
BlockScopedVariableExcludes = 107455,
ParameterExcludes = 107455,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
PropertyExcludes = 0,
EnumMemberExcludes = 900095,
FunctionExcludes = 106927,
ClassExcludes = 899519,
InterfaceExcludes = 792968,
RegularEnumExcludes = 899327,
ConstEnumExcludes = 899967,
ValueModuleExcludes = 106639,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
NamespaceModuleExcludes = 0,
MethodExcludes = 99263,
GetAccessorExcludes = 41919,
SetAccessorExcludes = 74687,
TypeParameterExcludes = 530920,
TypeAliasExcludes = 793064,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
+17 -17
View File
@@ -1956,28 +1956,28 @@ declare namespace ts {
JSContainer = 67108864,
Enum = 384,
Variable = 3,
Value = 107455,
Type = 793064,
Value = 67216319,
Type = 67901928,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 107454,
BlockScopedVariableExcludes = 107455,
ParameterExcludes = 107455,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
PropertyExcludes = 0,
EnumMemberExcludes = 900095,
FunctionExcludes = 106927,
ClassExcludes = 899519,
InterfaceExcludes = 792968,
RegularEnumExcludes = 899327,
ConstEnumExcludes = 899967,
ValueModuleExcludes = 106639,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
NamespaceModuleExcludes = 0,
MethodExcludes = 99263,
GetAccessorExcludes = 41919,
SetAccessorExcludes = 74687,
TypeParameterExcludes = 530920,
TypeAliasExcludes = 793064,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
@@ -0,0 +1,57 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
=== tests/cases/conformance/salsa/work.js ===
Outer.Inner = function () {}
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
x: 1,
>x : Symbol(x, Decl(work.js, 1, 25))
m() { }
>m : Symbol(m, Decl(work.js, 2, 9))
}
=== tests/cases/conformance/salsa/use.js ===
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(use.js, 1, 3))
inner.x
>inner.x : Symbol(x, Decl(work.js, 1, 25))
>inner : Symbol(inner, Decl(use.js, 1, 3))
>x : Symbol(x, Decl(work.js, 1, 25))
inner.m()
>inner.m : Symbol(m, Decl(work.js, 2, 9))
>inner : Symbol(inner, Decl(use.js, 1, 3))
>m : Symbol(m, Decl(work.js, 2, 9))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(use.js, 4, 3))
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
inno.x
>inno.x : Symbol(x, Decl(work.js, 1, 25))
>inno : Symbol(inno, Decl(use.js, 4, 3))
>x : Symbol(x, Decl(work.js, 1, 25))
inno.m()
>inno.m : Symbol(m, Decl(work.js, 2, 9))
>inno : Symbol(inno, Decl(use.js, 4, 3))
>m : Symbol(m, Decl(work.js, 2, 9))
@@ -0,0 +1,66 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : typeof Outer
>{} : typeof Outer
=== tests/cases/conformance/salsa/work.js ===
Outer.Inner = function () {}
>Outer.Inner = function () {} : () => void
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
>function () {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
>prototype : any
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
>x : number
>1 : 1
m() { }
>m : () => void
}
=== tests/cases/conformance/salsa/use.js ===
/** @type {Outer.Inner} */
var inner
>inner : { [x: string]: any; x: number; m(): void; }
inner.x
>inner.x : number
>inner : { [x: string]: any; x: number; m(): void; }
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { [x: string]: any; x: number; m(): void; }
>m : () => void
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
inno.x
>inno.x : number
>inno : { [x: string]: any; x: number; m(): void; }
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : { [x: string]: any; x: number; m(): void; }
>m : () => void
@@ -0,0 +1,49 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
Outer.Inner = class {
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
>Inner : Symbol(Inner, Decl(a.js, 0, 15))
constructor() {
this.x = 1
>this.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>this : Symbol((Anonymous class), Decl(a.js, 2, 13))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
}
m() { }
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
}
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(a.js, 10, 3))
inner.x
>inner.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
inner.m()
>inner.m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(a.js, 13, 3))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
>Inner : Symbol(Inner, Decl(a.js, 0, 15))
inno.x
>inno.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>inno : Symbol(inno, Decl(a.js, 13, 3))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
inno.m()
>inno.m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
>inno : Symbol(inno, Decl(a.js, 13, 3))
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
@@ -0,0 +1,57 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>{} : { [x: string]: any; Inner: typeof (Anonymous class); }
Outer.Inner = class {
>Outer.Inner = class { constructor() { this.x = 1 } m() { }} : typeof (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>Inner : typeof (Anonymous class)
>class { constructor() { this.x = 1 } m() { }} : typeof (Anonymous class)
constructor() {
this.x = 1
>this.x = 1 : 1
>this.x : number
>this : this
>x : number
>1 : 1
}
m() { }
>m : () => void
}
/** @type {Outer.Inner} */
var inner
>inner : (Anonymous class)
inner.x
>inner.x : number
>inner : (Anonymous class)
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : (Anonymous class)
>m : () => void
var inno = new Outer.Inner()
>inno : (Anonymous class)
>new Outer.Inner() : (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>Inner : typeof (Anonymous class)
inno.x
>inno.x : number
>inno : (Anonymous class)
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : (Anonymous class)
>m : () => void
@@ -0,0 +1,53 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
Outer.Inner = function () {}
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
x: 1,
>x : Symbol(x, Decl(a.js, 3, 25))
m() { }
>m : Symbol(m, Decl(a.js, 4, 9))
}
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(a.js, 9, 3))
inner.x
>inner.x : Symbol(x, Decl(a.js, 3, 25))
>inner : Symbol(inner, Decl(a.js, 9, 3))
>x : Symbol(x, Decl(a.js, 3, 25))
inner.m()
>inner.m : Symbol(m, Decl(a.js, 4, 9))
>inner : Symbol(inner, Decl(a.js, 9, 3))
>m : Symbol(m, Decl(a.js, 4, 9))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(a.js, 12, 3))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
inno.x
>inno.x : Symbol(x, Decl(a.js, 3, 25))
>inno : Symbol(inno, Decl(a.js, 12, 3))
>x : Symbol(x, Decl(a.js, 3, 25))
inno.m()
>inno.m : Symbol(m, Decl(a.js, 4, 9))
>inno : Symbol(inno, Decl(a.js, 12, 3))
>m : Symbol(m, Decl(a.js, 4, 9))
@@ -0,0 +1,62 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : { [x: string]: any; Inner: () => void; }
>{} : { [x: string]: any; Inner: () => void; }
Outer.Inner = function () {}
>Outer.Inner = function () {} : () => void
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>function () {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
>x : number
>1 : 1
m() { }
>m : () => void
}
/** @type {Outer.Inner} */
var inner
>inner : { [x: string]: any; x: number; m(): void; }
inner.x
>inner.x : number
>inner : { [x: string]: any; x: number; m(): void; }
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { [x: string]: any; x: number; m(): void; }
>m : () => void
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
inno.x
>inno.x : number
>inno : { [x: string]: any; x: number; m(): void; }
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : { [x: string]: any; x: number; m(): void; }
>m : () => void
@@ -0,0 +1,23 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: def.js
var Outer = {};
// @Filename: work.js
Outer.Inner = function () {}
Outer.Inner.prototype = {
x: 1,
m() { }
}
// @Filename: use.js
/** @type {Outer.Inner} */
var inner
inner.x
inner.m()
var inno = new Outer.Inner()
inno.x
inno.m()
@@ -0,0 +1,20 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: a.js
var Outer = {};
Outer.Inner = class {
constructor() {
this.x = 1
}
m() { }
}
/** @type {Outer.Inner} */
var inner
inner.x
inner.m()
var inno = new Outer.Inner()
inno.x
inno.m()
@@ -0,0 +1,19 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: a.js
var Outer = {};
Outer.Inner = function () {}
Outer.Inner.prototype = {
x: 1,
m() { }
}
/** @type {Outer.Inner} */
var inner
inner.x
inner.m()
var inno = new Outer.Inner()
inno.x
inno.m()