diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 58e097e70c2..ca4407e9007 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12170,6 +12170,19 @@ namespace ts { } function getWidenedProperty(prop: Symbol, context: WideningContext | undefined): Symbol { + if (!(prop.flags & SymbolFlags.Property)) { + // Since get accessors already widen their return value there is no need to + // widen accessor based properties here. + return prop; + } + if (prop.flags & SymbolFlags.JSContainer) { + const node = prop.declarations && first(prop.declarations); + const init = getAssignedJavascriptInitializer(node); + if (init && init.kind !== SyntaxKind.ObjectLiteralExpression) { + // for JS special declarations, the only kind of initializer that will widen is object literals + return prop; + } + } const original = getTypeOfSymbol(prop); const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined); const widened = getWidenedTypeWithContext(original, propContext); @@ -12190,9 +12203,7 @@ namespace ts { function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext | undefined): Type { const members = createSymbolTable(); for (const prop of getPropertiesOfObjectType(type)) { - // Since get accessors already widen their return value there is no need to - // widen accessor based properties here. - members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop, context) : prop); + members.set(prop.escapedName, getWidenedProperty(prop, context)); } if (context) { for (const prop of getPropertiesOfContext(context)) { @@ -15984,10 +15995,10 @@ namespace ts { const decl = getDeclarationOfJSInitializer(node); if (decl) { // a JS object literal whose declaration's symbol has exports is a JS namespace - const symbol = getMergedSymbol(decl.symbol); + const symbol = getSymbolOfNode(decl); if (symbol && hasEntries(symbol.exports)) { propertiesTable = symbol.exports; - symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol))); + symbol.exports.forEach(s => propertiesArray.push(getMergedSymbol(s))); return createObjectLiteralType(); } } diff --git a/tests/baselines/reference/typeFromPropertyAssignment25.symbols b/tests/baselines/reference/typeFromPropertyAssignment25.symbols new file mode 100644 index 00000000000..a98333e97d0 --- /dev/null +++ b/tests/baselines/reference/typeFromPropertyAssignment25.symbols @@ -0,0 +1,62 @@ +=== tests/cases/conformance/salsa/bug24703.js === +var Common = {}; +>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16)) + +Common.I = class { +>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16)) +>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16)) +>I : Symbol(Common.I, Decl(bug24703.js, 0, 16)) + + constructor() { + this.i = 1 +>this.i : Symbol(I.i, Decl(bug24703.js, 2, 19)) +>this : Symbol(I, Decl(bug24703.js, 1, 10)) +>i : Symbol(I.i, Decl(bug24703.js, 2, 19)) + } +} +Common.O = class extends Common.I { +>Common.O : Symbol(Common.O, Decl(bug24703.js, 5, 1)) +>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16)) +>O : Symbol(Common.O, Decl(bug24703.js, 5, 1)) +>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16)) +>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16)) +>I : Symbol(Common.I, Decl(bug24703.js, 0, 16)) + + constructor() { + super() +>super : Symbol(I, Decl(bug24703.js, 1, 10)) + + this.o = 2 +>this.o : Symbol(O.o, Decl(bug24703.js, 8, 15)) +>this : Symbol(O, Decl(bug24703.js, 6, 10)) +>o : Symbol(O.o, Decl(bug24703.js, 8, 15)) + } +} +var o = new Common.O() +>o : Symbol(o, Decl(bug24703.js, 12, 3)) +>Common.O : Symbol(Common.O, Decl(bug24703.js, 5, 1)) +>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16)) +>O : Symbol(Common.O, Decl(bug24703.js, 5, 1)) + +var i = new Common.I() +>i : Symbol(i, Decl(bug24703.js, 13, 3)) +>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16)) +>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16)) +>I : Symbol(Common.I, Decl(bug24703.js, 0, 16)) + +o.i +>o.i : Symbol(I.i, Decl(bug24703.js, 2, 19)) +>o : Symbol(o, Decl(bug24703.js, 12, 3)) +>i : Symbol(I.i, Decl(bug24703.js, 2, 19)) + +o.o +>o.o : Symbol(O.o, Decl(bug24703.js, 8, 15)) +>o : Symbol(o, Decl(bug24703.js, 12, 3)) +>o : Symbol(O.o, Decl(bug24703.js, 8, 15)) + +i.i +>i.i : Symbol(I.i, Decl(bug24703.js, 2, 19)) +>i : Symbol(i, Decl(bug24703.js, 13, 3)) +>i : Symbol(I.i, Decl(bug24703.js, 2, 19)) + + diff --git a/tests/baselines/reference/typeFromPropertyAssignment25.types b/tests/baselines/reference/typeFromPropertyAssignment25.types new file mode 100644 index 00000000000..e5c4a2066e7 --- /dev/null +++ b/tests/baselines/reference/typeFromPropertyAssignment25.types @@ -0,0 +1,74 @@ +=== tests/cases/conformance/salsa/bug24703.js === +var Common = {}; +>Common : { [x: string]: any; I: typeof I; O: typeof O; } +>{} : { [x: string]: any; I: typeof I; O: typeof O; } + +Common.I = class { +>Common.I = class { constructor() { this.i = 1 }} : typeof I +>Common.I : typeof I +>Common : { [x: string]: any; I: typeof I; O: typeof O; } +>I : typeof I +>class { constructor() { this.i = 1 }} : typeof I + + constructor() { + this.i = 1 +>this.i = 1 : 1 +>this.i : number +>this : this +>i : number +>1 : 1 + } +} +Common.O = class extends Common.I { +>Common.O = class extends Common.I { constructor() { super() this.o = 2 }} : typeof O +>Common.O : typeof O +>Common : { [x: string]: any; I: typeof I; O: typeof O; } +>O : typeof O +>class extends Common.I { constructor() { super() this.o = 2 }} : typeof O +>Common.I : I +>Common : { [x: string]: any; I: typeof I; O: typeof O; } +>I : typeof I + + constructor() { + super() +>super() : void +>super : typeof I + + this.o = 2 +>this.o = 2 : 2 +>this.o : number +>this : this +>o : number +>2 : 2 + } +} +var o = new Common.O() +>o : O +>new Common.O() : O +>Common.O : typeof O +>Common : { [x: string]: any; I: typeof I; O: typeof O; } +>O : typeof O + +var i = new Common.I() +>i : I +>new Common.I() : I +>Common.I : typeof I +>Common : { [x: string]: any; I: typeof I; O: typeof O; } +>I : typeof I + +o.i +>o.i : number +>o : O +>i : number + +o.o +>o.o : number +>o : O +>o : number + +i.i +>i.i : number +>i : I +>i : number + + diff --git a/tests/cases/conformance/salsa/typeFromPropertyAssignment25.ts b/tests/cases/conformance/salsa/typeFromPropertyAssignment25.ts new file mode 100644 index 00000000000..37c24366da9 --- /dev/null +++ b/tests/cases/conformance/salsa/typeFromPropertyAssignment25.ts @@ -0,0 +1,22 @@ +// @noEmit: true +// @checkJs: true +// @allowJs: true +// @Filename: bug24703.js +var Common = {}; +Common.I = class { + constructor() { + this.i = 1 + } +} +Common.O = class extends Common.I { + constructor() { + super() + this.o = 2 + } +} +var o = new Common.O() +var i = new Common.I() +o.i +o.o +i.i +