Allow multiple class base types; intersect them, as with interfaces (#23123)

This commit is contained in:
Wesley Wigham 2018-04-03 16:08:52 -07:00 committed by GitHub
parent a4593fd6db
commit 78ba32a110
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 133 additions and 6 deletions

View File

@ -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) {

View File

@ -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 = () => { }
}

View File

@ -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;

View File

@ -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))
}

View File

@ -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
}

View File

@ -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 = () => { }
}