diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 376bc3d3df0..5f0ab1680cf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16509,26 +16509,25 @@ namespace ts { if (!(prop.parent.flags & SymbolFlags.Class)) { return false; } - let classType = getTypeOfSymbol(prop.parent) as InterfaceType; + let classType = getTypeOfSymbol(prop.parent); while (true) { - classType = getSuperClass(classType); + classType = classType.symbol && getSuperClass(classType as InterfaceType); if (!classType) { return false; } - const superProperty = getPropertyOfObjectType(classType, prop.escapedName); + const superProperty = getPropertyOfType(classType, prop.escapedName); if (superProperty && superProperty.valueDeclaration) { return true; } } } - function getSuperClass(classType: InterfaceType): InterfaceType | undefined { + function getSuperClass(classType: InterfaceType): Type | undefined { const x = getBaseTypes(classType); if (x.length === 0) { return undefined; } - Debug.assert(x.length === 1); - return x[0] as InterfaceType; + return getIntersectionType(x); } function reportNonexistentProperty(propNode: Identifier, containingType: Type) { diff --git a/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.errors.txt b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.errors.txt new file mode 100644 index 00000000000..f760cf9bf2a --- /dev/null +++ b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.errors.txt @@ -0,0 +1,16 @@ +tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts(8,30): error TS2448: Block-scoped variable 'handleIntersection' used before its declaration. + + +==== tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts (1 errors) ==== + interface Bar { } + interface Baz { } + interface Q { } + interface Foo extends Bar, Baz { } + class Foo { } + + export default class extends Foo { + readonly observer = this.handleIntersection; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2448: Block-scoped variable 'handleIntersection' used before its declaration. + readonly handleIntersection = () => { } + } \ No newline at end of file diff --git a/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.js b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.js new file mode 100644 index 00000000000..201572a8221 --- /dev/null +++ b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.js @@ -0,0 +1,41 @@ +//// [classMergedWithInterfaceMultipleBasesNoError.ts] +interface Bar { } +interface Baz { } +interface Q { } +interface Foo extends Bar, Baz { } +class Foo { } + +export default class extends Foo { + readonly observer = this.handleIntersection; + readonly handleIntersection = () => { } +} + +//// [classMergedWithInterfaceMultipleBasesNoError.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +exports.__esModule = true; +var Foo = /** @class */ (function () { + function Foo() { + } + return Foo; +}()); +var default_1 = /** @class */ (function (_super) { + __extends(default_1, _super); + function default_1() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.observer = _this.handleIntersection; + _this.handleIntersection = function () { }; + return _this; + } + return default_1; +}(Foo)); +exports["default"] = default_1; diff --git a/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.symbols b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.symbols new file mode 100644 index 00000000000..9087a045082 --- /dev/null +++ b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.symbols @@ -0,0 +1,30 @@ +=== tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts === +interface Bar { } +>Bar : Symbol(Bar, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 0, 0)) + +interface Baz { } +>Baz : Symbol(Baz, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 0, 17)) + +interface Q { } +>Q : Symbol(Q, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 1, 17)) + +interface Foo extends Bar, Baz { } +>Foo : Symbol(Foo, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 2, 15), Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 3, 34)) +>Bar : Symbol(Bar, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 0, 0)) +>Baz : Symbol(Baz, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 0, 17)) + +class Foo { } +>Foo : Symbol(Foo, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 2, 15), Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 3, 34)) + +export default class extends Foo { +>Foo : Symbol(Foo, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 2, 15), Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 3, 34)) + + readonly observer = this.handleIntersection; +>observer : Symbol(default.observer, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 6, 34)) +>this.handleIntersection : Symbol(default.handleIntersection, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 7, 48)) +>this : Symbol(default, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 4, 13)) +>handleIntersection : Symbol(default.handleIntersection, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 7, 48)) + + readonly handleIntersection = () => { } +>handleIntersection : Symbol(default.handleIntersection, Decl(classMergedWithInterfaceMultipleBasesNoError.ts, 7, 48)) +} diff --git a/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.types b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.types new file mode 100644 index 00000000000..874f70a2e13 --- /dev/null +++ b/tests/baselines/reference/classMergedWithInterfaceMultipleBasesNoError.types @@ -0,0 +1,31 @@ +=== tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts === +interface Bar { } +>Bar : Bar + +interface Baz { } +>Baz : Baz + +interface Q { } +>Q : Q + +interface Foo extends Bar, Baz { } +>Foo : Foo +>Bar : Bar +>Baz : Baz + +class Foo { } +>Foo : Foo + +export default class extends Foo { +>Foo : Foo + + readonly observer = this.handleIntersection; +>observer : () => void +>this.handleIntersection : () => void +>this : this +>handleIntersection : () => void + + readonly handleIntersection = () => { } +>handleIntersection : () => void +>() => { } : () => void +} diff --git a/tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts b/tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts new file mode 100644 index 00000000000..53f0a982319 --- /dev/null +++ b/tests/cases/compiler/classMergedWithInterfaceMultipleBasesNoError.ts @@ -0,0 +1,10 @@ +interface Bar { } +interface Baz { } +interface Q { } +interface Foo extends Bar, Baz { } +class Foo { } + +export default class extends Foo { + readonly observer = this.handleIntersection; + readonly handleIntersection = () => { } +} \ No newline at end of file