From c9ac15ae56ff55dd6b8ae4bd00c929ecf489f2ec Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 26 Mar 2018 13:42:34 -0700 Subject: [PATCH] In JS, this assignments in constructors are preferred and nullable initializers become any (#22882) * First draft:in js, constructor declaration is preferred * Add tests * initializer of null|undefined gives any in JS Also move this-assignment fixes out of binder. I'm going to put it in the checker instead. * In JS, initializer null|undefined: any, []: any[] * First draft of js prefer-ctor-types overhaul * Update tests, update baselines * Improve readability of constructor-type preference * Cleanup: Remove TODO and duplication * Add noImplicitAny errors * Add comment --- src/compiler/checker.ts | 59 ++++- ...ringClassMembersFromAssignments.errors.txt | 148 +++++++++++ .../inferringClassMembersFromAssignments.js | 22 +- ...ferringClassMembersFromAssignments.symbols | 202 +++++++++------ ...inferringClassMembersFromAssignments.types | 69 ++++- .../typeFromJSConstructor.errors.txt | 52 ++++ .../reference/typeFromJSConstructor.symbols | 111 ++++++++ .../reference/typeFromJSConstructor.types | 165 ++++++++++++ .../typeFromJSInitializer.errors.txt | 75 ++++++ .../reference/typeFromJSInitializer.symbols | 171 +++++++++++++ .../reference/typeFromJSInitializer.types | 241 ++++++++++++++++++ .../typeFromPropertyAssignment22.errors.txt | 10 +- .../typeFromPropertyAssignment22.symbols | 2 +- .../typeFromPropertyAssignment22.types | 24 +- .../inferringClassMembersFromAssignments.ts | 13 +- .../salsa/typeFromJSConstructor.ts | 36 +++ .../salsa/typeFromJSInitializer.ts | 59 +++++ .../salsa/typeFromPropertyAssignment22.ts | 2 +- 18 files changed, 1340 insertions(+), 121 deletions(-) create mode 100644 tests/baselines/reference/inferringClassMembersFromAssignments.errors.txt create mode 100644 tests/baselines/reference/typeFromJSConstructor.errors.txt create mode 100644 tests/baselines/reference/typeFromJSConstructor.symbols create mode 100644 tests/baselines/reference/typeFromJSConstructor.types create mode 100644 tests/baselines/reference/typeFromJSInitializer.errors.txt create mode 100644 tests/baselines/reference/typeFromJSInitializer.symbols create mode 100644 tests/baselines/reference/typeFromJSInitializer.types create mode 100644 tests/cases/conformance/salsa/typeFromJSConstructor.ts create mode 100644 tests/cases/conformance/salsa/typeFromJSInitializer.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 35204060c32..e56447b85ac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4255,10 +4255,12 @@ namespace ts { return getWidenedLiteralType(checkExpressionCached(specialDeclaration)); } const types: Type[] = []; + let constructorTypes: Type[]; let definedInConstructor = false; let definedInMethod = false; let jsDocType: Type; for (const declaration of symbol.declarations) { + let declarationInConstructor = false; const expression = declaration.kind === SyntaxKind.BinaryExpression ? declaration : declaration.kind === SyntaxKind.PropertyAccessExpression ? getAncestor(declaration, SyntaxKind.BinaryExpression) : undefined; @@ -4271,9 +4273,10 @@ namespace ts { const thisContainer = getThisContainer(expression, /*includeArrowFunctions*/ false); // Properties defined in a constructor (or javascript constructor function) don't get undefined added. // Function expressions that are assigned to the prototype count as methods. - if (thisContainer.kind === SyntaxKind.Constructor || + declarationInConstructor = thisContainer.kind === SyntaxKind.Constructor || thisContainer.kind === SyntaxKind.FunctionDeclaration || - (thisContainer.kind === SyntaxKind.FunctionExpression && !isPrototypePropertyAssignment(thisContainer.parent))) { + (thisContainer.kind === SyntaxKind.FunctionExpression && !isPrototypePropertyAssignment(thisContainer.parent)); + if (declarationInConstructor) { definedInConstructor = true; } else { @@ -4296,14 +4299,37 @@ namespace ts { } else if (!jsDocType) { // If we don't have an explicit JSDoc type, get the type from the expression. - types.push(getWidenedLiteralType(checkExpressionCached(expression.right))); + const type = getWidenedLiteralType(checkExpressionCached(expression.right)); + let anyedType = type; + if (isEmptyArrayLiteralType(type)) { + anyedType = anyArrayType; + if (noImplicitAny) { + reportImplicitAnyError(expression, anyArrayType); + } + } + types.push(anyedType); + if (declarationInConstructor) { + (constructorTypes || (constructorTypes = [])).push(anyedType); + } } } - - const type = jsDocType || getUnionType(types, UnionReduction.Subtype); - return getWidenedType(addOptionality(type, definedInMethod && !definedInConstructor)); + let type = jsDocType; + if (!type) { + // use only the constructor types unless only null | undefined (including widening variants) were assigned there + const sourceTypes = some(constructorTypes, t => !!(t.flags & ~(TypeFlags.Nullable | TypeFlags.ContainsWideningType))) ? constructorTypes : types; + type = getUnionType(sourceTypes, UnionReduction.Subtype); + } + const widened = getWidenedType(addOptionality(type, definedInMethod && !definedInConstructor)); + if (filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType) { + if (noImplicitAny) { + reportImplicitAnyError(symbol.valueDeclaration, anyType); + } + return anyType; + } + return widened; } + // Return the type implied by a binding pattern element. This is the type of the initializer of the element if // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding // pattern. Otherwise, it is the type any. @@ -11394,6 +11420,7 @@ namespace ts { const typeAsString = typeToString(getWidenedType(type)); let diagnostic: DiagnosticMessage; switch (declaration.kind) { + case SyntaxKind.BinaryExpression: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: diagnostic = Diagnostics.Member_0_implicitly_has_an_1_type; @@ -19689,11 +19716,27 @@ namespace ts { } function checkDeclarationInitializer(declaration: HasExpressionInitializer) { - const initializer = isInJavaScriptFile(declaration) && getDeclaredJavascriptInitializer(declaration) || declaration.initializer; + const inJs = isInJavaScriptFile(declaration); + const initializer = inJs && getDeclaredJavascriptInitializer(declaration) || declaration.initializer; const type = getTypeOfExpression(initializer, /*cache*/ true); - return getCombinedNodeFlags(declaration) & NodeFlags.Const || + const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const || (getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration)) || isTypeAssertion(initializer) ? type : getWidenedLiteralType(type); + if (inJs) { + if (widened.flags & TypeFlags.Nullable) { + if (noImplicitAny) { + reportImplicitAnyError(declaration, anyType); + } + return anyType; + } + else if (isEmptyArrayLiteralType(widened)) { + if (noImplicitAny) { + reportImplicitAnyError(declaration, anyArrayType); + } + return anyArrayType; + } + } + return widened; } function isLiteralOfContextualType(candidateType: Type, contextualType: Type): boolean { diff --git a/tests/baselines/reference/inferringClassMembersFromAssignments.errors.txt b/tests/baselines/reference/inferringClassMembersFromAssignments.errors.txt new file mode 100644 index 00000000000..48fa2cdb9d3 --- /dev/null +++ b/tests/baselines/reference/inferringClassMembersFromAssignments.errors.txt @@ -0,0 +1,148 @@ +tests/cases/conformance/salsa/a.js(14,13): error TS7008: Member 'inMethodNullable' implicitly has an 'any' type. +tests/cases/conformance/salsa/a.js(20,9): error TS2322: Type '"string"' is not assignable to type 'number'. +tests/cases/conformance/salsa/a.js(39,9): error TS2322: Type 'false' is not assignable to type 'number'. +tests/cases/conformance/salsa/a.js(93,13): error TS2334: 'this' cannot be referenced in a static property initializer. +tests/cases/conformance/salsa/a.js(96,13): error TS2334: 'this' cannot be referenced in a static property initializer. + + +==== tests/cases/conformance/salsa/a.js (5 errors) ==== + class C { + constructor() { + if (Math.random()) { + this.inConstructor = 0; + } + else { + this.inConstructor = "string" + } + this.inMultiple = 0; + } + method() { + if (Math.random()) { + this.inMethod = 0; + this.inMethodNullable = null; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS7008: Member 'inMethodNullable' implicitly has an 'any' type. + } + else { + this.inMethod = "string" + this.inMethodNullable = undefined; + } + this.inMultiple = "string"; + ~~~~~~~~~~~~~~~ +!!! error TS2322: Type '"string"' is not assignable to type 'number'. + this.inMultipleMethods = "string"; + + var action = () => { + if (Math.random()) { + this.inNestedArrowFunction = 0; + } + else { + this.inNestedArrowFunction = "string" + } + }; + } + get() { + if (Math.random()) { + this.inGetter = 0; + } + else { + this.inGetter = "string" + } + this.inMultiple = false; + ~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'false' is not assignable to type 'number'. + this.inMultipleMethods = false; + } + set() { + if (Math.random()) { + this.inSetter = 0; + } + else { + this.inSetter = "string" + } + } + prop = () => { + if (Math.random()) { + this.inPropertyDeclaration = 0; + } + else { + this.inPropertyDeclaration = "string" + } + } + static method() { + if (Math.random()) { + this.inStaticMethod = 0; + } + else { + this.inStaticMethod = "string" + } + + var action = () => { + if (Math.random()) { + this.inStaticNestedArrowFunction = 0; + } + else { + this.inStaticNestedArrowFunction = "string" + } + }; + } + static get() { + if (Math.random()) { + this.inStaticGetter = 0; + } + else { + this.inStaticGetter = "string" + } + } + static set() { + if (Math.random()) { + this.inStaticSetter = 0; + } + else { + this.inStaticSetter = "string" + } + } + static prop = () => { + if (Math.random()) { + this.inStaticPropertyDeclaration = 0; + ~~~~ +!!! error TS2334: 'this' cannot be referenced in a static property initializer. + } + else { + this.inStaticPropertyDeclaration = "string" + ~~~~ +!!! error TS2334: 'this' cannot be referenced in a static property initializer. + } + } + } + +==== tests/cases/conformance/salsa/b.ts (0 errors) ==== + var c = new C(); + + var stringOrNumber: string | number; + var stringOrNumber = c.inConstructor; + + var stringOrNumberOrUndefined: string | number | undefined; + + var stringOrNumberOrUndefined = c.inMethod; + var stringOrNumberOrUndefined = c.inGetter; + var stringOrNumberOrUndefined = c.inSetter; + var stringOrNumberOrUndefined = c.inPropertyDeclaration; + var stringOrNumberOrUndefined = c.inNestedArrowFunction + + var stringOrNumberOrBoolean: string | number | boolean; + + var number: number; + var number = c.inMultiple; + var stringOrBooleanOrUndefined : string | boolean | undefined; + var stringOrBooleanOrUndefined = c.inMultipleMethods; + var any: any; + var any = c.inMethodNullable; + + + var stringOrNumberOrUndefined = C.inStaticMethod; + var stringOrNumberOrUndefined = C.inStaticGetter; + var stringOrNumberOrUndefined = C.inStaticSetter; + var stringOrNumberOrUndefined = C.inStaticPropertyDeclaration; + var stringOrNumberOrUndefined = C.inStaticNestedArrowFunction; + \ No newline at end of file diff --git a/tests/baselines/reference/inferringClassMembersFromAssignments.js b/tests/baselines/reference/inferringClassMembersFromAssignments.js index 90f87734b2e..e8d25a917dd 100644 --- a/tests/baselines/reference/inferringClassMembersFromAssignments.js +++ b/tests/baselines/reference/inferringClassMembersFromAssignments.js @@ -14,11 +14,14 @@ class C { method() { if (Math.random()) { this.inMethod = 0; + this.inMethodNullable = null; } else { this.inMethod = "string" + this.inMethodNullable = undefined; } this.inMultiple = "string"; + this.inMultipleMethods = "string"; var action = () => { if (Math.random()) { @@ -37,6 +40,7 @@ class C { this.inGetter = "string" } this.inMultiple = false; + this.inMultipleMethods = false; } set() { if (Math.random()) { @@ -113,7 +117,12 @@ var stringOrNumberOrUndefined = c.inNestedArrowFunction var stringOrNumberOrBoolean: string | number | boolean; -var stringOrNumberOrBoolean = c.inMultiple; +var number: number; +var number = c.inMultiple; +var stringOrBooleanOrUndefined : string | boolean | undefined; +var stringOrBooleanOrUndefined = c.inMultipleMethods; +var any: any; +var any = c.inMethodNullable; var stringOrNumberOrUndefined = C.inStaticMethod; @@ -148,11 +157,14 @@ var C = /** @class */ (function () { var _this = this; if (Math.random()) { this.inMethod = 0; + this.inMethodNullable = null; } else { this.inMethod = "string"; + this.inMethodNullable = undefined; } this.inMultiple = "string"; + this.inMultipleMethods = "string"; var action = function () { if (Math.random()) { _this.inNestedArrowFunction = 0; @@ -170,6 +182,7 @@ var C = /** @class */ (function () { this.inGetter = "string"; } this.inMultiple = false; + this.inMultipleMethods = false; }; C.prototype.set = function () { if (Math.random()) { @@ -232,7 +245,12 @@ var stringOrNumberOrUndefined = c.inSetter; var stringOrNumberOrUndefined = c.inPropertyDeclaration; var stringOrNumberOrUndefined = c.inNestedArrowFunction; var stringOrNumberOrBoolean; -var stringOrNumberOrBoolean = c.inMultiple; +var number; +var number = c.inMultiple; +var stringOrBooleanOrUndefined; +var stringOrBooleanOrUndefined = c.inMultipleMethods; +var any; +var any = c.inMethodNullable; var stringOrNumberOrUndefined = C.inStaticMethod; var stringOrNumberOrUndefined = C.inStaticGetter; var stringOrNumberOrUndefined = C.inStaticSetter; diff --git a/tests/baselines/reference/inferringClassMembersFromAssignments.symbols b/tests/baselines/reference/inferringClassMembersFromAssignments.symbols index a2f18b84a07..316b9f08f7c 100644 --- a/tests/baselines/reference/inferringClassMembersFromAssignments.symbols +++ b/tests/baselines/reference/inferringClassMembersFromAssignments.symbols @@ -20,9 +20,9 @@ class C { >inConstructor : Symbol(C.inConstructor, Decl(a.js, 2, 28), Decl(a.js, 5, 14)) } this.inMultiple = 0; ->this.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +>this.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +>inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) } method() { >method : Symbol(C.method, Decl(a.js, 9, 5)) @@ -33,23 +33,39 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inMethod = 0; ->this.inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 14, 14)) +>this.inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 15, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 14, 14)) +>inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 15, 14)) + + this.inMethodNullable = null; +>this.inMethodNullable : Symbol(C.inMethodNullable, Decl(a.js, 12, 30), Decl(a.js, 16, 36)) +>this : Symbol(C, Decl(a.js, 0, 0)) +>inMethodNullable : Symbol(C.inMethodNullable, Decl(a.js, 12, 30), Decl(a.js, 16, 36)) } else { this.inMethod = "string" ->this.inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 14, 14)) +>this.inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 15, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 14, 14)) +>inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 15, 14)) + + this.inMethodNullable = undefined; +>this.inMethodNullable : Symbol(C.inMethodNullable, Decl(a.js, 12, 30), Decl(a.js, 16, 36)) +>this : Symbol(C, Decl(a.js, 0, 0)) +>inMethodNullable : Symbol(C.inMethodNullable, Decl(a.js, 12, 30), Decl(a.js, 16, 36)) +>undefined : Symbol(undefined) } this.inMultiple = "string"; ->this.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +>this.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +>inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) + + this.inMultipleMethods = "string"; +>this.inMultipleMethods : Symbol(C.inMultipleMethods, Decl(a.js, 19, 35), Decl(a.js, 38, 32)) +>this : Symbol(C, Decl(a.js, 0, 0)) +>inMultipleMethods : Symbol(C.inMultipleMethods, Decl(a.js, 19, 35), Decl(a.js, 38, 32)) var action = () => { ->action : Symbol(action, Decl(a.js, 19, 11)) +>action : Symbol(action, Decl(a.js, 22, 11)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -57,20 +73,20 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inNestedArrowFunction = 0; ->this.inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 20, 32), Decl(a.js, 23, 18)) +>this.inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 23, 32), Decl(a.js, 26, 18)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 20, 32), Decl(a.js, 23, 18)) +>inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 23, 32), Decl(a.js, 26, 18)) } else { this.inNestedArrowFunction = "string" ->this.inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 20, 32), Decl(a.js, 23, 18)) +>this.inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 23, 32), Decl(a.js, 26, 18)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 20, 32), Decl(a.js, 23, 18)) +>inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 23, 32), Decl(a.js, 26, 18)) } }; } get() { ->get : Symbol(C.get, Decl(a.js, 27, 5)) +>get : Symbol(C.get, Decl(a.js, 30, 5)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -78,23 +94,28 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inGetter = 0; ->this.inGetter : Symbol(C.inGetter, Decl(a.js, 29, 28), Decl(a.js, 32, 14)) +>this.inGetter : Symbol(C.inGetter, Decl(a.js, 32, 28), Decl(a.js, 35, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inGetter : Symbol(C.inGetter, Decl(a.js, 29, 28), Decl(a.js, 32, 14)) +>inGetter : Symbol(C.inGetter, Decl(a.js, 32, 28), Decl(a.js, 35, 14)) } else { this.inGetter = "string" ->this.inGetter : Symbol(C.inGetter, Decl(a.js, 29, 28), Decl(a.js, 32, 14)) +>this.inGetter : Symbol(C.inGetter, Decl(a.js, 32, 28), Decl(a.js, 35, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inGetter : Symbol(C.inGetter, Decl(a.js, 29, 28), Decl(a.js, 32, 14)) +>inGetter : Symbol(C.inGetter, Decl(a.js, 32, 28), Decl(a.js, 35, 14)) } this.inMultiple = false; ->this.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +>this.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +>inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) + + this.inMultipleMethods = false; +>this.inMultipleMethods : Symbol(C.inMultipleMethods, Decl(a.js, 19, 35), Decl(a.js, 38, 32)) +>this : Symbol(C, Decl(a.js, 0, 0)) +>inMultipleMethods : Symbol(C.inMultipleMethods, Decl(a.js, 19, 35), Decl(a.js, 38, 32)) } set() { ->set : Symbol(C.set, Decl(a.js, 36, 5)) +>set : Symbol(C.set, Decl(a.js, 40, 5)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -102,19 +123,19 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inSetter = 0; ->this.inSetter : Symbol(C.inSetter, Decl(a.js, 38, 28), Decl(a.js, 41, 14)) +>this.inSetter : Symbol(C.inSetter, Decl(a.js, 42, 28), Decl(a.js, 45, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inSetter : Symbol(C.inSetter, Decl(a.js, 38, 28), Decl(a.js, 41, 14)) +>inSetter : Symbol(C.inSetter, Decl(a.js, 42, 28), Decl(a.js, 45, 14)) } else { this.inSetter = "string" ->this.inSetter : Symbol(C.inSetter, Decl(a.js, 38, 28), Decl(a.js, 41, 14)) +>this.inSetter : Symbol(C.inSetter, Decl(a.js, 42, 28), Decl(a.js, 45, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inSetter : Symbol(C.inSetter, Decl(a.js, 38, 28), Decl(a.js, 41, 14)) +>inSetter : Symbol(C.inSetter, Decl(a.js, 42, 28), Decl(a.js, 45, 14)) } } prop = () => { ->prop : Symbol(C.prop, Decl(a.js, 44, 5)) +>prop : Symbol(C.prop, Decl(a.js, 48, 5)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -122,19 +143,19 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inPropertyDeclaration = 0; ->this.inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 46, 28), Decl(a.js, 49, 14)) +>this.inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 50, 28), Decl(a.js, 53, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 46, 28), Decl(a.js, 49, 14)) +>inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 50, 28), Decl(a.js, 53, 14)) } else { this.inPropertyDeclaration = "string" ->this.inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 46, 28), Decl(a.js, 49, 14)) +>this.inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 50, 28), Decl(a.js, 53, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 46, 28), Decl(a.js, 49, 14)) +>inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 50, 28), Decl(a.js, 53, 14)) } } static method() { ->method : Symbol(C.method, Decl(a.js, 52, 5)) +>method : Symbol(C.method, Decl(a.js, 56, 5)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -142,19 +163,19 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inStaticMethod = 0; ->this.inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 54, 28), Decl(a.js, 57, 14)) +>this.inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 58, 28), Decl(a.js, 61, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 54, 28), Decl(a.js, 57, 14)) +>inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 58, 28), Decl(a.js, 61, 14)) } else { this.inStaticMethod = "string" ->this.inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 54, 28), Decl(a.js, 57, 14)) +>this.inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 58, 28), Decl(a.js, 61, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 54, 28), Decl(a.js, 57, 14)) +>inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 58, 28), Decl(a.js, 61, 14)) } var action = () => { ->action : Symbol(action, Decl(a.js, 61, 11)) +>action : Symbol(action, Decl(a.js, 65, 11)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -162,20 +183,20 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inStaticNestedArrowFunction = 0; ->this.inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 62, 32), Decl(a.js, 65, 18)) +>this.inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 66, 32), Decl(a.js, 69, 18)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 62, 32), Decl(a.js, 65, 18)) +>inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 66, 32), Decl(a.js, 69, 18)) } else { this.inStaticNestedArrowFunction = "string" ->this.inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 62, 32), Decl(a.js, 65, 18)) +>this.inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 66, 32), Decl(a.js, 69, 18)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 62, 32), Decl(a.js, 65, 18)) +>inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 66, 32), Decl(a.js, 69, 18)) } }; } static get() { ->get : Symbol(C.get, Decl(a.js, 69, 5)) +>get : Symbol(C.get, Decl(a.js, 73, 5)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -183,19 +204,19 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inStaticGetter = 0; ->this.inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 71, 28), Decl(a.js, 74, 14)) +>this.inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 75, 28), Decl(a.js, 78, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 71, 28), Decl(a.js, 74, 14)) +>inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 75, 28), Decl(a.js, 78, 14)) } else { this.inStaticGetter = "string" ->this.inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 71, 28), Decl(a.js, 74, 14)) +>this.inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 75, 28), Decl(a.js, 78, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 71, 28), Decl(a.js, 74, 14)) +>inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 75, 28), Decl(a.js, 78, 14)) } } static set() { ->set : Symbol(C.set, Decl(a.js, 77, 5)) +>set : Symbol(C.set, Decl(a.js, 81, 5)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -203,19 +224,19 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inStaticSetter = 0; ->this.inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 79, 28), Decl(a.js, 82, 14)) +>this.inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 83, 28), Decl(a.js, 86, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 79, 28), Decl(a.js, 82, 14)) +>inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 83, 28), Decl(a.js, 86, 14)) } else { this.inStaticSetter = "string" ->this.inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 79, 28), Decl(a.js, 82, 14)) +>this.inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 83, 28), Decl(a.js, 86, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 79, 28), Decl(a.js, 82, 14)) +>inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 83, 28), Decl(a.js, 86, 14)) } } static prop = () => { ->prop : Symbol(C.prop, Decl(a.js, 85, 5)) +>prop : Symbol(C.prop, Decl(a.js, 89, 5)) if (Math.random()) { >Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --)) @@ -223,15 +244,15 @@ class C { >random : Symbol(Math.random, Decl(lib.d.ts, --, --)) this.inStaticPropertyDeclaration = 0; ->this.inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 87, 28), Decl(a.js, 90, 14)) +>this.inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 91, 28), Decl(a.js, 94, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 87, 28), Decl(a.js, 90, 14)) +>inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 91, 28), Decl(a.js, 94, 14)) } else { this.inStaticPropertyDeclaration = "string" ->this.inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 87, 28), Decl(a.js, 90, 14)) +>this.inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 91, 28), Decl(a.js, 94, 14)) >this : Symbol(C, Decl(a.js, 0, 0)) ->inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 87, 28), Decl(a.js, 90, 14)) +>inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 91, 28), Decl(a.js, 94, 14)) } } } @@ -255,71 +276,92 @@ var stringOrNumberOrUndefined: string | number | undefined; var stringOrNumberOrUndefined = c.inMethod; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->c.inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 14, 14)) +>c.inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 15, 14)) >c : Symbol(c, Decl(b.ts, 0, 3)) ->inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 14, 14)) +>inMethod : Symbol(C.inMethod, Decl(a.js, 11, 28), Decl(a.js, 15, 14)) var stringOrNumberOrUndefined = c.inGetter; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->c.inGetter : Symbol(C.inGetter, Decl(a.js, 29, 28), Decl(a.js, 32, 14)) +>c.inGetter : Symbol(C.inGetter, Decl(a.js, 32, 28), Decl(a.js, 35, 14)) >c : Symbol(c, Decl(b.ts, 0, 3)) ->inGetter : Symbol(C.inGetter, Decl(a.js, 29, 28), Decl(a.js, 32, 14)) +>inGetter : Symbol(C.inGetter, Decl(a.js, 32, 28), Decl(a.js, 35, 14)) var stringOrNumberOrUndefined = c.inSetter; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->c.inSetter : Symbol(C.inSetter, Decl(a.js, 38, 28), Decl(a.js, 41, 14)) +>c.inSetter : Symbol(C.inSetter, Decl(a.js, 42, 28), Decl(a.js, 45, 14)) >c : Symbol(c, Decl(b.ts, 0, 3)) ->inSetter : Symbol(C.inSetter, Decl(a.js, 38, 28), Decl(a.js, 41, 14)) +>inSetter : Symbol(C.inSetter, Decl(a.js, 42, 28), Decl(a.js, 45, 14)) var stringOrNumberOrUndefined = c.inPropertyDeclaration; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->c.inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 46, 28), Decl(a.js, 49, 14)) +>c.inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 50, 28), Decl(a.js, 53, 14)) >c : Symbol(c, Decl(b.ts, 0, 3)) ->inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 46, 28), Decl(a.js, 49, 14)) +>inPropertyDeclaration : Symbol(C.inPropertyDeclaration, Decl(a.js, 50, 28), Decl(a.js, 53, 14)) var stringOrNumberOrUndefined = c.inNestedArrowFunction >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->c.inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 20, 32), Decl(a.js, 23, 18)) +>c.inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 23, 32), Decl(a.js, 26, 18)) >c : Symbol(c, Decl(b.ts, 0, 3)) ->inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 20, 32), Decl(a.js, 23, 18)) +>inNestedArrowFunction : Symbol(C.inNestedArrowFunction, Decl(a.js, 23, 32), Decl(a.js, 26, 18)) var stringOrNumberOrBoolean: string | number | boolean; ->stringOrNumberOrBoolean : Symbol(stringOrNumberOrBoolean, Decl(b.ts, 13, 3), Decl(b.ts, 15, 3)) +>stringOrNumberOrBoolean : Symbol(stringOrNumberOrBoolean, Decl(b.ts, 13, 3)) -var stringOrNumberOrBoolean = c.inMultiple; ->stringOrNumberOrBoolean : Symbol(stringOrNumberOrBoolean, Decl(b.ts, 13, 3), Decl(b.ts, 15, 3)) ->c.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +var number: number; +>number : Symbol(number, Decl(b.ts, 15, 3), Decl(b.ts, 16, 3)) + +var number = c.inMultiple; +>number : Symbol(number, Decl(b.ts, 15, 3), Decl(b.ts, 16, 3)) +>c.inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) >c : Symbol(c, Decl(b.ts, 0, 3)) ->inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 16, 9), Decl(a.js, 34, 9)) +>inMultiple : Symbol(C.inMultiple, Decl(a.js, 7, 9), Decl(a.js, 18, 9), Decl(a.js, 37, 9)) + +var stringOrBooleanOrUndefined : string | boolean | undefined; +>stringOrBooleanOrUndefined : Symbol(stringOrBooleanOrUndefined, Decl(b.ts, 17, 3), Decl(b.ts, 18, 3)) + +var stringOrBooleanOrUndefined = c.inMultipleMethods; +>stringOrBooleanOrUndefined : Symbol(stringOrBooleanOrUndefined, Decl(b.ts, 17, 3), Decl(b.ts, 18, 3)) +>c.inMultipleMethods : Symbol(C.inMultipleMethods, Decl(a.js, 19, 35), Decl(a.js, 38, 32)) +>c : Symbol(c, Decl(b.ts, 0, 3)) +>inMultipleMethods : Symbol(C.inMultipleMethods, Decl(a.js, 19, 35), Decl(a.js, 38, 32)) + +var any: any; +>any : Symbol(any, Decl(b.ts, 19, 3), Decl(b.ts, 20, 3)) + +var any = c.inMethodNullable; +>any : Symbol(any, Decl(b.ts, 19, 3), Decl(b.ts, 20, 3)) +>c.inMethodNullable : Symbol(C.inMethodNullable, Decl(a.js, 12, 30), Decl(a.js, 16, 36)) +>c : Symbol(c, Decl(b.ts, 0, 3)) +>inMethodNullable : Symbol(C.inMethodNullable, Decl(a.js, 12, 30), Decl(a.js, 16, 36)) var stringOrNumberOrUndefined = C.inStaticMethod; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->C.inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 54, 28), Decl(a.js, 57, 14)) +>C.inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 58, 28), Decl(a.js, 61, 14)) >C : Symbol(C, Decl(a.js, 0, 0)) ->inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 54, 28), Decl(a.js, 57, 14)) +>inStaticMethod : Symbol(C.inStaticMethod, Decl(a.js, 58, 28), Decl(a.js, 61, 14)) var stringOrNumberOrUndefined = C.inStaticGetter; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->C.inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 71, 28), Decl(a.js, 74, 14)) +>C.inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 75, 28), Decl(a.js, 78, 14)) >C : Symbol(C, Decl(a.js, 0, 0)) ->inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 71, 28), Decl(a.js, 74, 14)) +>inStaticGetter : Symbol(C.inStaticGetter, Decl(a.js, 75, 28), Decl(a.js, 78, 14)) var stringOrNumberOrUndefined = C.inStaticSetter; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->C.inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 79, 28), Decl(a.js, 82, 14)) +>C.inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 83, 28), Decl(a.js, 86, 14)) >C : Symbol(C, Decl(a.js, 0, 0)) ->inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 79, 28), Decl(a.js, 82, 14)) +>inStaticSetter : Symbol(C.inStaticSetter, Decl(a.js, 83, 28), Decl(a.js, 86, 14)) var stringOrNumberOrUndefined = C.inStaticPropertyDeclaration; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->C.inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 87, 28), Decl(a.js, 90, 14)) +>C.inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 91, 28), Decl(a.js, 94, 14)) >C : Symbol(C, Decl(a.js, 0, 0)) ->inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 87, 28), Decl(a.js, 90, 14)) +>inStaticPropertyDeclaration : Symbol(C.inStaticPropertyDeclaration, Decl(a.js, 91, 28), Decl(a.js, 94, 14)) var stringOrNumberOrUndefined = C.inStaticNestedArrowFunction; >stringOrNumberOrUndefined : Symbol(stringOrNumberOrUndefined, Decl(b.ts, 5, 3), Decl(b.ts, 7, 3), Decl(b.ts, 8, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3) ... and 6 more) ->C.inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 62, 32), Decl(a.js, 65, 18)) +>C.inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 66, 32), Decl(a.js, 69, 18)) >C : Symbol(C, Decl(a.js, 0, 0)) ->inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 62, 32), Decl(a.js, 65, 18)) +>inStaticNestedArrowFunction : Symbol(C.inStaticNestedArrowFunction, Decl(a.js, 66, 32), Decl(a.js, 69, 18)) diff --git a/tests/baselines/reference/inferringClassMembersFromAssignments.types b/tests/baselines/reference/inferringClassMembersFromAssignments.types index e462a04d198..3d168707fe6 100644 --- a/tests/baselines/reference/inferringClassMembersFromAssignments.types +++ b/tests/baselines/reference/inferringClassMembersFromAssignments.types @@ -26,9 +26,9 @@ class C { } this.inMultiple = 0; >this.inMultiple = 0 : 0 ->this.inMultiple : string | number | boolean +>this.inMultiple : number >this : this ->inMultiple : string | number | boolean +>inMultiple : number >0 : 0 } method() { @@ -46,6 +46,13 @@ class C { >this : this >inMethod : string | number | undefined >0 : 0 + + this.inMethodNullable = null; +>this.inMethodNullable = null : null +>this.inMethodNullable : any +>this : this +>inMethodNullable : any +>null : null } else { this.inMethod = "string" @@ -54,12 +61,26 @@ class C { >this : this >inMethod : string | number | undefined >"string" : "string" + + this.inMethodNullable = undefined; +>this.inMethodNullable = undefined : undefined +>this.inMethodNullable : any +>this : this +>inMethodNullable : any +>undefined : undefined } this.inMultiple = "string"; >this.inMultiple = "string" : "string" ->this.inMultiple : string | number | boolean +>this.inMultiple : number >this : this ->inMultiple : string | number | boolean +>inMultiple : number +>"string" : "string" + + this.inMultipleMethods = "string"; +>this.inMultipleMethods = "string" : "string" +>this.inMultipleMethods : string | boolean | undefined +>this : this +>inMultipleMethods : string | boolean | undefined >"string" : "string" var action = () => { @@ -115,9 +136,16 @@ class C { } this.inMultiple = false; >this.inMultiple = false : false ->this.inMultiple : string | number | boolean +>this.inMultiple : number >this : this ->inMultiple : string | number | boolean +>inMultiple : number +>false : false + + this.inMultipleMethods = false; +>this.inMultipleMethods = false : false +>this.inMultipleMethods : string | boolean | undefined +>this : this +>inMultipleMethods : string | boolean | undefined >false : false } set() { @@ -352,11 +380,32 @@ var stringOrNumberOrUndefined = c.inNestedArrowFunction var stringOrNumberOrBoolean: string | number | boolean; >stringOrNumberOrBoolean : string | number | boolean -var stringOrNumberOrBoolean = c.inMultiple; ->stringOrNumberOrBoolean : string | number | boolean ->c.inMultiple : string | number | boolean +var number: number; +>number : number + +var number = c.inMultiple; +>number : number +>c.inMultiple : number >c : C ->inMultiple : string | number | boolean +>inMultiple : number + +var stringOrBooleanOrUndefined : string | boolean | undefined; +>stringOrBooleanOrUndefined : string | boolean | undefined + +var stringOrBooleanOrUndefined = c.inMultipleMethods; +>stringOrBooleanOrUndefined : string | boolean | undefined +>c.inMultipleMethods : string | boolean | undefined +>c : C +>inMultipleMethods : string | boolean | undefined + +var any: any; +>any : any + +var any = c.inMethodNullable; +>any : any +>c.inMethodNullable : any +>c : C +>inMethodNullable : any var stringOrNumberOrUndefined = C.inStaticMethod; diff --git a/tests/baselines/reference/typeFromJSConstructor.errors.txt b/tests/baselines/reference/typeFromJSConstructor.errors.txt new file mode 100644 index 00000000000..ffcf5393f51 --- /dev/null +++ b/tests/baselines/reference/typeFromJSConstructor.errors.txt @@ -0,0 +1,52 @@ +tests/cases/conformance/salsa/a.js(10,5): error TS7008: Member 'twices' implicitly has an 'any[]' type. +tests/cases/conformance/salsa/a.js(14,5): error TS2322: Type '"hi"' is not assignable to type 'number'. +tests/cases/conformance/salsa/a.js(21,5): error TS2322: Type 'false' is not assignable to type 'number'. +tests/cases/conformance/salsa/a.js(24,5): error TS2322: Type 'null' is not assignable to type 'string | undefined'. +tests/cases/conformance/salsa/a.js(25,5): error TS2322: Type 'false' is not assignable to type 'string | undefined'. +tests/cases/conformance/salsa/a.js(26,5): error TS2531: Object is possibly 'null'. + + +==== tests/cases/conformance/salsa/a.js (6 errors) ==== + function Installer () { + // arg: number + this.arg = 0 + // unknown: string | boolean | null + this.unknown = null + // twice: string | undefined + this.twice = undefined + this.twice = 'hi' + // twices: any[] | null + this.twices = [] + ~~~~~~~~~~~~~~~~ +!!! error TS7008: Member 'twices' implicitly has an 'any[]' type. + this.twices = null + } + Installer.prototype.first = function () { + this.arg = 'hi' // error + ~~~~~~~~ +!!! error TS2322: Type '"hi"' is not assignable to type 'number'. + this.unknown = 'hi' // ok + this.newProperty = 1 // ok: number | boolean + this.twice = undefined // ok + this.twice = 'hi' // ok + } + Installer.prototype.second = function () { + this.arg = false // error + ~~~~~~~~ +!!! error TS2322: Type 'false' is not assignable to type 'number'. + this.unknown = false // ok + this.newProperty = false // ok + this.twice = null // error + ~~~~~~~~~~ +!!! error TS2322: Type 'null' is not assignable to type 'string | undefined'. + this.twice = false // error + ~~~~~~~~~~ +!!! error TS2322: Type 'false' is not assignable to type 'string | undefined'. + this.twices.push(1) // error: Object is possibly null + ~~~~~~~~~~~ +!!! error TS2531: Object is possibly 'null'. + if (this.twices != null) { + this.twices.push('hi') + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/typeFromJSConstructor.symbols b/tests/baselines/reference/typeFromJSConstructor.symbols new file mode 100644 index 00000000000..541eeada65f --- /dev/null +++ b/tests/baselines/reference/typeFromJSConstructor.symbols @@ -0,0 +1,111 @@ +=== tests/cases/conformance/salsa/a.js === +function Installer () { +>Installer : Symbol(Installer, Decl(a.js, 0, 0)) + + // arg: number + this.arg = 0 +>arg : Symbol(Installer.arg, Decl(a.js, 0, 23), Decl(a.js, 12, 41), Decl(a.js, 19, 42)) + + // unknown: string | boolean | null + this.unknown = null +>unknown : Symbol(Installer.unknown, Decl(a.js, 2, 16), Decl(a.js, 13, 19), Decl(a.js, 20, 20)) + + // twice: string | undefined + this.twice = undefined +>twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) +>undefined : Symbol(undefined) + + this.twice = 'hi' +>twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) + + // twices: any[] | null + this.twices = [] +>twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) + + this.twices = null +>twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) +} +Installer.prototype.first = function () { +>Installer.prototype : Symbol(Installer.first, Decl(a.js, 11, 1)) +>Installer : Symbol(Installer, Decl(a.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --)) +>first : Symbol(Installer.first, Decl(a.js, 11, 1)) + + this.arg = 'hi' // error +>this.arg : Symbol(Installer.arg, Decl(a.js, 0, 23), Decl(a.js, 12, 41), Decl(a.js, 19, 42)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>arg : Symbol(Installer.arg, Decl(a.js, 0, 23), Decl(a.js, 12, 41), Decl(a.js, 19, 42)) + + this.unknown = 'hi' // ok +>this.unknown : Symbol(Installer.unknown, Decl(a.js, 2, 16), Decl(a.js, 13, 19), Decl(a.js, 20, 20)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>unknown : Symbol(Installer.unknown, Decl(a.js, 2, 16), Decl(a.js, 13, 19), Decl(a.js, 20, 20)) + + this.newProperty = 1 // ok: number | boolean +>this.newProperty : Symbol(Installer.newProperty, Decl(a.js, 14, 23), Decl(a.js, 21, 24)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>newProperty : Symbol(Installer.newProperty, Decl(a.js, 14, 23), Decl(a.js, 21, 24)) + + this.twice = undefined // ok +>this.twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) +>undefined : Symbol(undefined) + + this.twice = 'hi' // ok +>this.twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) +} +Installer.prototype.second = function () { +>Installer.prototype : Symbol(Installer.second, Decl(a.js, 18, 1)) +>Installer : Symbol(Installer, Decl(a.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --)) +>second : Symbol(Installer.second, Decl(a.js, 18, 1)) + + this.arg = false // error +>this.arg : Symbol(Installer.arg, Decl(a.js, 0, 23), Decl(a.js, 12, 41), Decl(a.js, 19, 42)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>arg : Symbol(Installer.arg, Decl(a.js, 0, 23), Decl(a.js, 12, 41), Decl(a.js, 19, 42)) + + this.unknown = false // ok +>this.unknown : Symbol(Installer.unknown, Decl(a.js, 2, 16), Decl(a.js, 13, 19), Decl(a.js, 20, 20)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>unknown : Symbol(Installer.unknown, Decl(a.js, 2, 16), Decl(a.js, 13, 19), Decl(a.js, 20, 20)) + + this.newProperty = false // ok +>this.newProperty : Symbol(Installer.newProperty, Decl(a.js, 14, 23), Decl(a.js, 21, 24)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>newProperty : Symbol(Installer.newProperty, Decl(a.js, 14, 23), Decl(a.js, 21, 24)) + + this.twice = null // error +>this.twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) + + this.twice = false // error +>this.twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>twice : Symbol(Installer.twice, Decl(a.js, 4, 23), Decl(a.js, 6, 26), Decl(a.js, 15, 24), Decl(a.js, 16, 26), Decl(a.js, 22, 28) ... and 1 more) + + this.twices.push(1) // error: Object is possibly null +>this.twices.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>this.twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + + if (this.twices != null) { +>this.twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) + + this.twices.push('hi') +>this.twices.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>this.twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) +>this : Symbol(Installer, Decl(a.js, 0, 0)) +>twices : Symbol(Installer.twices, Decl(a.js, 7, 21), Decl(a.js, 9, 20)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + } +} + diff --git a/tests/baselines/reference/typeFromJSConstructor.types b/tests/baselines/reference/typeFromJSConstructor.types new file mode 100644 index 00000000000..f7dd925ed5c --- /dev/null +++ b/tests/baselines/reference/typeFromJSConstructor.types @@ -0,0 +1,165 @@ +=== tests/cases/conformance/salsa/a.js === +function Installer () { +>Installer : () => void + + // arg: number + this.arg = 0 +>this.arg = 0 : 0 +>this.arg : any +>this : any +>arg : any +>0 : 0 + + // unknown: string | boolean | null + this.unknown = null +>this.unknown = null : null +>this.unknown : any +>this : any +>unknown : any +>null : null + + // twice: string | undefined + this.twice = undefined +>this.twice = undefined : undefined +>this.twice : any +>this : any +>twice : any +>undefined : undefined + + this.twice = 'hi' +>this.twice = 'hi' : "hi" +>this.twice : any +>this : any +>twice : any +>'hi' : "hi" + + // twices: any[] | null + this.twices = [] +>this.twices = [] : never[] +>this.twices : any +>this : any +>twices : any +>[] : never[] + + this.twices = null +>this.twices = null : null +>this.twices : any +>this : any +>twices : any +>null : null +} +Installer.prototype.first = function () { +>Installer.prototype.first = function () { this.arg = 'hi' // error this.unknown = 'hi' // ok this.newProperty = 1 // ok: number | boolean this.twice = undefined // ok this.twice = 'hi' // ok} : () => void +>Installer.prototype.first : any +>Installer.prototype : any +>Installer : () => void +>prototype : any +>first : any +>function () { this.arg = 'hi' // error this.unknown = 'hi' // ok this.newProperty = 1 // ok: number | boolean this.twice = undefined // ok this.twice = 'hi' // ok} : () => void + + this.arg = 'hi' // error +>this.arg = 'hi' : "hi" +>this.arg : number +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>arg : number +>'hi' : "hi" + + this.unknown = 'hi' // ok +>this.unknown = 'hi' : "hi" +>this.unknown : string | boolean | null +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>unknown : string | boolean | null +>'hi' : "hi" + + this.newProperty = 1 // ok: number | boolean +>this.newProperty = 1 : 1 +>this.newProperty : number | boolean | undefined +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>newProperty : number | boolean | undefined +>1 : 1 + + this.twice = undefined // ok +>this.twice = undefined : undefined +>this.twice : string | undefined +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>twice : string | undefined +>undefined : undefined + + this.twice = 'hi' // ok +>this.twice = 'hi' : "hi" +>this.twice : string | undefined +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>twice : string | undefined +>'hi' : "hi" +} +Installer.prototype.second = function () { +>Installer.prototype.second = function () { this.arg = false // error this.unknown = false // ok this.newProperty = false // ok this.twice = null // error this.twice = false // error this.twices.push(1) // error: Object is possibly null if (this.twices != null) { this.twices.push('hi') }} : () => void +>Installer.prototype.second : any +>Installer.prototype : any +>Installer : () => void +>prototype : any +>second : any +>function () { this.arg = false // error this.unknown = false // ok this.newProperty = false // ok this.twice = null // error this.twice = false // error this.twices.push(1) // error: Object is possibly null if (this.twices != null) { this.twices.push('hi') }} : () => void + + this.arg = false // error +>this.arg = false : false +>this.arg : number +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>arg : number +>false : false + + this.unknown = false // ok +>this.unknown = false : false +>this.unknown : string | boolean | null +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>unknown : string | boolean | null +>false : false + + this.newProperty = false // ok +>this.newProperty = false : false +>this.newProperty : number | boolean | undefined +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>newProperty : number | boolean | undefined +>false : false + + this.twice = null // error +>this.twice = null : null +>this.twice : string | undefined +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>twice : string | undefined +>null : null + + this.twice = false // error +>this.twice = false : false +>this.twice : string | undefined +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>twice : string | undefined +>false : false + + this.twices.push(1) // error: Object is possibly null +>this.twices.push(1) : number +>this.twices.push : (...items: any[]) => number +>this.twices : any[] | null +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>twices : any[] | null +>push : (...items: any[]) => number +>1 : 1 + + if (this.twices != null) { +>this.twices != null : boolean +>this.twices : any[] | null +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>twices : any[] | null +>null : null + + this.twices.push('hi') +>this.twices.push('hi') : number +>this.twices.push : (...items: any[]) => number +>this.twices : any[] +>this : { arg: number; unknown: string | boolean | null; twice: string | undefined; twices: any[] | null; first: () => void; newProperty: number | boolean | undefined; second: () => void; } +>twices : any[] +>push : (...items: any[]) => number +>'hi' : "hi" + } +} + diff --git a/tests/baselines/reference/typeFromJSInitializer.errors.txt b/tests/baselines/reference/typeFromJSInitializer.errors.txt new file mode 100644 index 00000000000..08d66a2a9f3 --- /dev/null +++ b/tests/baselines/reference/typeFromJSInitializer.errors.txt @@ -0,0 +1,75 @@ +tests/cases/conformance/salsa/a.js(3,5): error TS7008: Member 'unknown' implicitly has an 'any' type. +tests/cases/conformance/salsa/a.js(4,5): error TS7008: Member 'unknowable' implicitly has an 'any' type. +tests/cases/conformance/salsa/a.js(5,5): error TS7008: Member 'empty' implicitly has an 'any[]' type. +tests/cases/conformance/salsa/a.js(25,12): error TS7006: Parameter 'a' implicitly has an 'any' type. +tests/cases/conformance/salsa/a.js(25,29): error TS7006: Parameter 'l' implicitly has an 'any[]' type. +tests/cases/conformance/salsa/a.js(37,5): error TS2322: Type '"error"' is not assignable to type 'number | undefined'. + + +==== tests/cases/conformance/salsa/a.js (6 errors) ==== + function A () { + // should get any on this-assignments in constructor + this.unknown = null + ~~~~~~~~~~~~~~~~~~~ +!!! error TS7008: Member 'unknown' implicitly has an 'any' type. + this.unknowable = undefined + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS7008: Member 'unknowable' implicitly has an 'any' type. + this.empty = [] + ~~~~~~~~~~~~~~~ +!!! error TS7008: Member 'empty' implicitly has an 'any[]' type. + } + var a = new A() + a.unknown = 1 + a.unknown = true + a.unknown = {} + a.unknown = 'hi' + a.unknowable = 1 + a.unknowable = true + a.unknowable = {} + a.unknowable = 'hi' + a.empty.push(1) + a.empty.push(true) + a.empty.push({}) + a.empty.push('hi') + + /** @type {number | undefined} */ + var n; + + // should get any on parameter initialisers + function f(a = null, b = n, l = []) { + ~~~~~~~~ +!!! error TS7006: Parameter 'a' implicitly has an 'any' type. + ~~~~~~ +!!! error TS7006: Parameter 'l' implicitly has an 'any[]' type. + // a should be any + a = undefined + a = null + a = 1 + a = true + a = {} + a = 'ok' + + // b should be number | undefined, not any + b = 1 + b = undefined + b = 'error' + ~ +!!! error TS2322: Type '"error"' is not assignable to type 'number | undefined'. + + // l should be any[] + l.push(1) + l.push('ok') + } + + // should get any on variable initialisers + var u = undefined; + var l = []; + u = undefined + u = 1 + u = true + u = {} + u = 'ok' + + l.push('ok') + \ No newline at end of file diff --git a/tests/baselines/reference/typeFromJSInitializer.symbols b/tests/baselines/reference/typeFromJSInitializer.symbols new file mode 100644 index 00000000000..3c9d9657421 --- /dev/null +++ b/tests/baselines/reference/typeFromJSInitializer.symbols @@ -0,0 +1,171 @@ +=== tests/cases/conformance/salsa/a.js === +function A () { +>A : Symbol(A, Decl(a.js, 0, 0)) + + // should get any on this-assignments in constructor + this.unknown = null +>unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) + + this.unknowable = undefined +>unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) +>undefined : Symbol(undefined) + + this.empty = [] +>empty : Symbol(A.empty, Decl(a.js, 3, 31)) +} +var a = new A() +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>A : Symbol(A, Decl(a.js, 0, 0)) + +a.unknown = 1 +>a.unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) + +a.unknown = true +>a.unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) + +a.unknown = {} +>a.unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) + +a.unknown = 'hi' +>a.unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknown : Symbol(A.unknown, Decl(a.js, 0, 15)) + +a.unknowable = 1 +>a.unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) + +a.unknowable = true +>a.unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) + +a.unknowable = {} +>a.unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) + +a.unknowable = 'hi' +>a.unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>unknowable : Symbol(A.unknowable, Decl(a.js, 2, 23)) + +a.empty.push(1) +>a.empty.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>a.empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + +a.empty.push(true) +>a.empty.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>a.empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + +a.empty.push({}) +>a.empty.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>a.empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + +a.empty.push('hi') +>a.empty.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>a.empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>a : Symbol(a, Decl(a.js, 6, 3), Decl(a.js, 8, 16)) +>empty : Symbol(A.empty, Decl(a.js, 3, 31)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + +/** @type {number | undefined} */ +var n; +>n : Symbol(n, Decl(a.js, 21, 3)) + +// should get any on parameter initialisers +function f(a = null, b = n, l = []) { +>f : Symbol(f, Decl(a.js, 21, 6)) +>a : Symbol(a, Decl(a.js, 24, 11)) +>b : Symbol(b, Decl(a.js, 24, 20)) +>n : Symbol(n, Decl(a.js, 21, 3)) +>l : Symbol(l, Decl(a.js, 24, 27)) + + // a should be any + a = undefined +>a : Symbol(a, Decl(a.js, 24, 11)) +>undefined : Symbol(undefined) + + a = null +>a : Symbol(a, Decl(a.js, 24, 11)) + + a = 1 +>a : Symbol(a, Decl(a.js, 24, 11)) + + a = true +>a : Symbol(a, Decl(a.js, 24, 11)) + + a = {} +>a : Symbol(a, Decl(a.js, 24, 11)) + + a = 'ok' +>a : Symbol(a, Decl(a.js, 24, 11)) + + // b should be number | undefined, not any + b = 1 +>b : Symbol(b, Decl(a.js, 24, 20)) + + b = undefined +>b : Symbol(b, Decl(a.js, 24, 20)) +>undefined : Symbol(undefined) + + b = 'error' +>b : Symbol(b, Decl(a.js, 24, 20)) + + // l should be any[] + l.push(1) +>l.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>l : Symbol(l, Decl(a.js, 24, 27)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + + l.push('ok') +>l.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>l : Symbol(l, Decl(a.js, 24, 27)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +} + +// should get any on variable initialisers +var u = undefined; +>u : Symbol(u, Decl(a.js, 44, 3)) +>undefined : Symbol(undefined) + +var l = []; +>l : Symbol(l, Decl(a.js, 45, 3)) + +u = undefined +>u : Symbol(u, Decl(a.js, 44, 3)) +>undefined : Symbol(undefined) + +u = 1 +>u : Symbol(u, Decl(a.js, 44, 3)) + +u = true +>u : Symbol(u, Decl(a.js, 44, 3)) + +u = {} +>u : Symbol(u, Decl(a.js, 44, 3)) + +u = 'ok' +>u : Symbol(u, Decl(a.js, 44, 3)) + +l.push('ok') +>l.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>l : Symbol(l, Decl(a.js, 45, 3)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/typeFromJSInitializer.types b/tests/baselines/reference/typeFromJSInitializer.types new file mode 100644 index 00000000000..cc994c9a616 --- /dev/null +++ b/tests/baselines/reference/typeFromJSInitializer.types @@ -0,0 +1,241 @@ +=== tests/cases/conformance/salsa/a.js === +function A () { +>A : () => void + + // should get any on this-assignments in constructor + this.unknown = null +>this.unknown = null : null +>this.unknown : any +>this : any +>unknown : any +>null : null + + this.unknowable = undefined +>this.unknowable = undefined : undefined +>this.unknowable : any +>this : any +>unknowable : any +>undefined : undefined + + this.empty = [] +>this.empty = [] : never[] +>this.empty : any +>this : any +>empty : any +>[] : never[] +} +var a = new A() +>a : { unknown: any; unknowable: any; empty: any[]; } +>new A() : { unknown: any; unknowable: any; empty: any[]; } +>A : () => void + +a.unknown = 1 +>a.unknown = 1 : 1 +>a.unknown : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknown : any +>1 : 1 + +a.unknown = true +>a.unknown = true : true +>a.unknown : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknown : any +>true : true + +a.unknown = {} +>a.unknown = {} : { [x: string]: any; } +>a.unknown : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknown : any +>{} : { [x: string]: any; } + +a.unknown = 'hi' +>a.unknown = 'hi' : "hi" +>a.unknown : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknown : any +>'hi' : "hi" + +a.unknowable = 1 +>a.unknowable = 1 : 1 +>a.unknowable : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknowable : any +>1 : 1 + +a.unknowable = true +>a.unknowable = true : true +>a.unknowable : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknowable : any +>true : true + +a.unknowable = {} +>a.unknowable = {} : { [x: string]: any; } +>a.unknowable : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknowable : any +>{} : { [x: string]: any; } + +a.unknowable = 'hi' +>a.unknowable = 'hi' : "hi" +>a.unknowable : any +>a : { unknown: any; unknowable: any; empty: any[]; } +>unknowable : any +>'hi' : "hi" + +a.empty.push(1) +>a.empty.push(1) : number +>a.empty.push : (...items: any[]) => number +>a.empty : any[] +>a : { unknown: any; unknowable: any; empty: any[]; } +>empty : any[] +>push : (...items: any[]) => number +>1 : 1 + +a.empty.push(true) +>a.empty.push(true) : number +>a.empty.push : (...items: any[]) => number +>a.empty : any[] +>a : { unknown: any; unknowable: any; empty: any[]; } +>empty : any[] +>push : (...items: any[]) => number +>true : true + +a.empty.push({}) +>a.empty.push({}) : number +>a.empty.push : (...items: any[]) => number +>a.empty : any[] +>a : { unknown: any; unknowable: any; empty: any[]; } +>empty : any[] +>push : (...items: any[]) => number +>{} : {} + +a.empty.push('hi') +>a.empty.push('hi') : number +>a.empty.push : (...items: any[]) => number +>a.empty : any[] +>a : { unknown: any; unknowable: any; empty: any[]; } +>empty : any[] +>push : (...items: any[]) => number +>'hi' : "hi" + +/** @type {number | undefined} */ +var n; +>n : number | undefined + +// should get any on parameter initialisers +function f(a = null, b = n, l = []) { +>f : (a?: any, b?: number | undefined, l?: any[]) => void +>a : any +>null : null +>b : number | undefined +>n : number | undefined +>l : any[] +>[] : never[] + + // a should be any + a = undefined +>a = undefined : undefined +>a : any +>undefined : undefined + + a = null +>a = null : null +>a : any +>null : null + + a = 1 +>a = 1 : 1 +>a : any +>1 : 1 + + a = true +>a = true : true +>a : any +>true : true + + a = {} +>a = {} : {} +>a : any +>{} : {} + + a = 'ok' +>a = 'ok' : "ok" +>a : any +>'ok' : "ok" + + // b should be number | undefined, not any + b = 1 +>b = 1 : 1 +>b : number | undefined +>1 : 1 + + b = undefined +>b = undefined : undefined +>b : number | undefined +>undefined : undefined + + b = 'error' +>b = 'error' : "error" +>b : number | undefined +>'error' : "error" + + // l should be any[] + l.push(1) +>l.push(1) : number +>l.push : (...items: any[]) => number +>l : any[] +>push : (...items: any[]) => number +>1 : 1 + + l.push('ok') +>l.push('ok') : number +>l.push : (...items: any[]) => number +>l : any[] +>push : (...items: any[]) => number +>'ok' : "ok" +} + +// should get any on variable initialisers +var u = undefined; +>u : any +>undefined : undefined + +var l = []; +>l : any[] +>[] : never[] + +u = undefined +>u = undefined : undefined +>u : any +>undefined : undefined + +u = 1 +>u = 1 : 1 +>u : any +>1 : 1 + +u = true +>u = true : true +>u : any +>true : true + +u = {} +>u = {} : {} +>u : any +>{} : {} + +u = 'ok' +>u = 'ok' : "ok" +>u : any +>'ok' : "ok" + +l.push('ok') +>l.push('ok') : number +>l.push : (...items: any[]) => number +>l : any[] +>push : (...items: any[]) => number +>'ok' : "ok" + diff --git a/tests/baselines/reference/typeFromPropertyAssignment22.errors.txt b/tests/baselines/reference/typeFromPropertyAssignment22.errors.txt index 969824cb33f..e688c37e30e 100644 --- a/tests/baselines/reference/typeFromPropertyAssignment22.errors.txt +++ b/tests/baselines/reference/typeFromPropertyAssignment22.errors.txt @@ -1,5 +1,4 @@ -tests/cases/conformance/salsa/npm-install.js(12,1): error TS2322: Type 'string | number' is not assignable to type 'number | undefined'. - Type 'string' is not assignable to type 'number | undefined'. +tests/cases/conformance/salsa/npm-install.js(7,9): error TS2322: Type '"hi"' is not assignable to type 'number'. ==== tests/cases/conformance/salsa/npm-install.js (1 errors) ==== @@ -10,12 +9,11 @@ tests/cases/conformance/salsa/npm-install.js(12,1): error TS2322: Type 'string | // ArrowFunction isn't treated as a this-container (args) => { this.args = 'hi' + ~~~~~~~~~ +!!! error TS2322: Type '"hi"' is not assignable to type 'number'. this.newProperty = 1 } } var i = new Installer() - i.newProperty = i.args // error, number | string =/> number | undefined - ~~~~~~~~~~~~~ -!!! error TS2322: Type 'string | number' is not assignable to type 'number | undefined'. -!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. + i.newProperty = i.args // ok, number ==> number | undefined \ No newline at end of file diff --git a/tests/baselines/reference/typeFromPropertyAssignment22.symbols b/tests/baselines/reference/typeFromPropertyAssignment22.symbols index 2591f0f5a73..1d43e3a4c27 100644 --- a/tests/baselines/reference/typeFromPropertyAssignment22.symbols +++ b/tests/baselines/reference/typeFromPropertyAssignment22.symbols @@ -31,7 +31,7 @@ var i = new Installer() >i : Symbol(i, Decl(npm-install.js, 10, 3)) >Installer : Symbol(Installer, Decl(npm-install.js, 0, 0)) -i.newProperty = i.args // error, number | string =/> number | undefined +i.newProperty = i.args // ok, number ==> number | undefined >i.newProperty : Symbol(Installer.newProperty, Decl(npm-install.js, 6, 24)) >i : Symbol(i, Decl(npm-install.js, 10, 3)) >newProperty : Symbol(Installer.newProperty, Decl(npm-install.js, 6, 24)) diff --git a/tests/baselines/reference/typeFromPropertyAssignment22.types b/tests/baselines/reference/typeFromPropertyAssignment22.types index 888a9f6efc4..56b1f8c9169 100644 --- a/tests/baselines/reference/typeFromPropertyAssignment22.types +++ b/tests/baselines/reference/typeFromPropertyAssignment22.types @@ -26,30 +26,30 @@ Installer.prototype.loadArgMetadata = function (next) { this.args = 'hi' >this.args = 'hi' : "hi" ->this.args : string | number ->this : { args: string | number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } ->args : string | number +>this.args : number +>this : { args: number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } +>args : number >'hi' : "hi" this.newProperty = 1 >this.newProperty = 1 : 1 >this.newProperty : number | undefined ->this : { args: string | number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } +>this : { args: number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } >newProperty : number | undefined >1 : 1 } } var i = new Installer() ->i : { args: string | number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } ->new Installer() : { args: string | number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } +>i : { args: number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } +>new Installer() : { args: number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } >Installer : () => void -i.newProperty = i.args // error, number | string =/> number | undefined ->i.newProperty = i.args : string | number +i.newProperty = i.args // ok, number ==> number | undefined +>i.newProperty = i.args : number >i.newProperty : number | undefined ->i : { args: string | number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } +>i : { args: number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } >newProperty : number | undefined ->i.args : string | number ->i : { args: string | number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } ->args : string | number +>i.args : number +>i : { args: number; loadArgMetadata: (next: any) => void; newProperty: number | undefined; } +>args : number diff --git a/tests/cases/conformance/salsa/inferringClassMembersFromAssignments.ts b/tests/cases/conformance/salsa/inferringClassMembersFromAssignments.ts index 9cf02a9c7dd..b6c12be6407 100644 --- a/tests/cases/conformance/salsa/inferringClassMembersFromAssignments.ts +++ b/tests/cases/conformance/salsa/inferringClassMembersFromAssignments.ts @@ -1,5 +1,7 @@ // @out: output.js // @allowJs: true +// @checkJs: true +// @noImplicitAny: true // @strictNullChecks: true // @filename: a.js @@ -16,11 +18,14 @@ class C { method() { if (Math.random()) { this.inMethod = 0; + this.inMethodNullable = null; } else { this.inMethod = "string" + this.inMethodNullable = undefined; } this.inMultiple = "string"; + this.inMultipleMethods = "string"; var action = () => { if (Math.random()) { @@ -39,6 +44,7 @@ class C { this.inGetter = "string" } this.inMultiple = false; + this.inMultipleMethods = false; } set() { if (Math.random()) { @@ -115,7 +121,12 @@ var stringOrNumberOrUndefined = c.inNestedArrowFunction var stringOrNumberOrBoolean: string | number | boolean; -var stringOrNumberOrBoolean = c.inMultiple; +var number: number; +var number = c.inMultiple; +var stringOrBooleanOrUndefined : string | boolean | undefined; +var stringOrBooleanOrUndefined = c.inMultipleMethods; +var any: any; +var any = c.inMethodNullable; var stringOrNumberOrUndefined = C.inStaticMethod; diff --git a/tests/cases/conformance/salsa/typeFromJSConstructor.ts b/tests/cases/conformance/salsa/typeFromJSConstructor.ts new file mode 100644 index 00000000000..241faec53e2 --- /dev/null +++ b/tests/cases/conformance/salsa/typeFromJSConstructor.ts @@ -0,0 +1,36 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @strictNullChecks: true +// @noImplicitAny: true +// @Filename: a.js +function Installer () { + // arg: number + this.arg = 0 + // unknown: string | boolean | null + this.unknown = null + // twice: string | undefined + this.twice = undefined + this.twice = 'hi' + // twices: any[] | null + this.twices = [] + this.twices = null +} +Installer.prototype.first = function () { + this.arg = 'hi' // error + this.unknown = 'hi' // ok + this.newProperty = 1 // ok: number | boolean + this.twice = undefined // ok + this.twice = 'hi' // ok +} +Installer.prototype.second = function () { + this.arg = false // error + this.unknown = false // ok + this.newProperty = false // ok + this.twice = null // error + this.twice = false // error + this.twices.push(1) // error: Object is possibly null + if (this.twices != null) { + this.twices.push('hi') + } +} diff --git a/tests/cases/conformance/salsa/typeFromJSInitializer.ts b/tests/cases/conformance/salsa/typeFromJSInitializer.ts new file mode 100644 index 00000000000..39d2edb39b3 --- /dev/null +++ b/tests/cases/conformance/salsa/typeFromJSInitializer.ts @@ -0,0 +1,59 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @strictNullChecks: true +// @noImplicitAny: true +// @Filename: a.js +function A () { + // should get any on this-assignments in constructor + this.unknown = null + this.unknowable = undefined + this.empty = [] +} +var a = new A() +a.unknown = 1 +a.unknown = true +a.unknown = {} +a.unknown = 'hi' +a.unknowable = 1 +a.unknowable = true +a.unknowable = {} +a.unknowable = 'hi' +a.empty.push(1) +a.empty.push(true) +a.empty.push({}) +a.empty.push('hi') + +/** @type {number | undefined} */ +var n; + +// should get any on parameter initialisers +function f(a = null, b = n, l = []) { + // a should be any + a = undefined + a = null + a = 1 + a = true + a = {} + a = 'ok' + + // b should be number | undefined, not any + b = 1 + b = undefined + b = 'error' + + // l should be any[] + l.push(1) + l.push('ok') +} + +// should get any on variable initialisers +var u = undefined; +var l = []; +u = undefined +u = 1 +u = true +u = {} +u = 'ok' + +l.push('ok') diff --git a/tests/cases/conformance/salsa/typeFromPropertyAssignment22.ts b/tests/cases/conformance/salsa/typeFromPropertyAssignment22.ts index 75bc2c62b90..4f64e611476 100644 --- a/tests/cases/conformance/salsa/typeFromPropertyAssignment22.ts +++ b/tests/cases/conformance/salsa/typeFromPropertyAssignment22.ts @@ -14,4 +14,4 @@ Installer.prototype.loadArgMetadata = function (next) { } } var i = new Installer() -i.newProperty = i.args // error, number | string =/> number | undefined +i.newProperty = i.args // ok, number ==> number | undefined