Merge pull request #5359 from Microsoft/merge-inherits-interface-members

Merge inherits interface members
This commit is contained in:
Nathan Shively-Sanders 2015-10-23 14:51:13 -07:00
commit d26a4c8a87
7 changed files with 438 additions and 18 deletions

View File

@ -2845,23 +2845,29 @@ namespace ts {
return type.resolvedBaseConstructorType;
}
function hasClassBaseType(type: InterfaceType): boolean {
return !!forEach(getBaseTypes(type), t => !!(t.symbol.flags & SymbolFlags.Class));
}
function getBaseTypes(type: InterfaceType): ObjectType[] {
let isClass = type.symbol.flags & SymbolFlags.Class;
let isInterface = type.symbol.flags & SymbolFlags.Interface;
if (!type.resolvedBaseTypes) {
if (type.symbol.flags & SymbolFlags.Class) {
if (!isClass && !isInterface) {
Debug.fail("type must be class or interface");
}
if (isClass) {
resolveBaseTypesOfClass(type);
}
else if (type.symbol.flags & SymbolFlags.Interface) {
if (isInterface) {
resolveBaseTypesOfInterface(type);
}
else {
Debug.fail("type must be class or interface");
}
}
return type.resolvedBaseTypes;
}
function resolveBaseTypesOfClass(type: InterfaceType): void {
type.resolvedBaseTypes = emptyArray;
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
let baseContructorType = getBaseConstructorTypeOfClass(type);
if (!(baseContructorType.flags & TypeFlags.ObjectType)) {
return;
@ -2897,11 +2903,16 @@ namespace ts {
typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
return;
}
type.resolvedBaseTypes = [baseType];
if (type.resolvedBaseTypes === emptyArray) {
type.resolvedBaseTypes = [baseType];
}
else {
type.resolvedBaseTypes.push(baseType);
}
}
function resolveBaseTypesOfInterface(type: InterfaceType): void {
type.resolvedBaseTypes = [];
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
for (let declaration of type.symbol.declarations) {
if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(<InterfaceDeclaration>declaration)) {
for (let node of getInterfaceBaseTypeNodes(<InterfaceDeclaration>declaration)) {
@ -2909,7 +2920,12 @@ namespace ts {
if (baseType !== unknownType) {
if (getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface)) {
if (type !== baseType && !hasBaseType(<InterfaceType>baseType, type)) {
type.resolvedBaseTypes.push(baseType);
if (type.resolvedBaseTypes === emptyArray) {
type.resolvedBaseTypes = [baseType];
}
else {
type.resolvedBaseTypes.push(baseType);
}
}
else {
error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
@ -3252,7 +3268,7 @@ namespace ts {
}
function getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
if (!getBaseTypes(classType).length) {
if (!hasClassBaseType(classType)) {
return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, false, false)];
}
let baseConstructorType = getBaseConstructorTypeOfClass(classType);

View File

@ -0,0 +1,96 @@
//// [mergedInheritedClassInterface.ts]
interface BaseInterface {
required: number;
optional?: number;
}
class BaseClass {
baseMethod() { }
baseNumber: number;
}
interface Child extends BaseInterface {
additional: number;
}
class Child extends BaseClass {
classNumber: number;
method() { }
}
interface ChildNoBaseClass extends BaseInterface {
additional2: string;
}
class ChildNoBaseClass {
classString: string;
method2() { }
}
class Grandchild extends ChildNoBaseClass {
}
// checks if properties actually were merged
var child : Child;
child.required;
child.optional;
child.additional;
child.baseNumber;
child.classNumber;
child.baseMethod();
child.method();
var grandchild: Grandchild;
grandchild.required;
grandchild.optional;
grandchild.additional2;
grandchild.classString;
grandchild.method2();
//// [mergedInheritedClassInterface.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var BaseClass = (function () {
function BaseClass() {
}
BaseClass.prototype.baseMethod = function () { };
return BaseClass;
})();
var Child = (function (_super) {
__extends(Child, _super);
function Child() {
_super.apply(this, arguments);
}
Child.prototype.method = function () { };
return Child;
})(BaseClass);
var ChildNoBaseClass = (function () {
function ChildNoBaseClass() {
}
ChildNoBaseClass.prototype.method2 = function () { };
return ChildNoBaseClass;
})();
var Grandchild = (function (_super) {
__extends(Grandchild, _super);
function Grandchild() {
_super.apply(this, arguments);
}
return Grandchild;
})(ChildNoBaseClass);
// checks if properties actually were merged
var child;
child.required;
child.optional;
child.additional;
child.baseNumber;
child.classNumber;
child.baseMethod();
child.method();
var grandchild;
grandchild.required;
grandchild.optional;
grandchild.additional2;
grandchild.classString;
grandchild.method2();

View File

@ -0,0 +1,130 @@
=== tests/cases/conformance/classes/classDeclarations/mergedInheritedClassInterface.ts ===
interface BaseInterface {
>BaseInterface : Symbol(BaseInterface, Decl(mergedInheritedClassInterface.ts, 0, 0))
required: number;
>required : Symbol(required, Decl(mergedInheritedClassInterface.ts, 0, 25))
optional?: number;
>optional : Symbol(optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
}
class BaseClass {
>BaseClass : Symbol(BaseClass, Decl(mergedInheritedClassInterface.ts, 3, 1))
baseMethod() { }
>baseMethod : Symbol(baseMethod, Decl(mergedInheritedClassInterface.ts, 5, 17))
baseNumber: number;
>baseNumber : Symbol(baseNumber, Decl(mergedInheritedClassInterface.ts, 6, 20))
}
interface Child extends BaseInterface {
>Child : Symbol(Child, Decl(mergedInheritedClassInterface.ts, 8, 1), Decl(mergedInheritedClassInterface.ts, 12, 1))
>BaseInterface : Symbol(BaseInterface, Decl(mergedInheritedClassInterface.ts, 0, 0))
additional: number;
>additional : Symbol(additional, Decl(mergedInheritedClassInterface.ts, 10, 39))
}
class Child extends BaseClass {
>Child : Symbol(Child, Decl(mergedInheritedClassInterface.ts, 8, 1), Decl(mergedInheritedClassInterface.ts, 12, 1))
>BaseClass : Symbol(BaseClass, Decl(mergedInheritedClassInterface.ts, 3, 1))
classNumber: number;
>classNumber : Symbol(classNumber, Decl(mergedInheritedClassInterface.ts, 14, 31))
method() { }
>method : Symbol(method, Decl(mergedInheritedClassInterface.ts, 15, 24))
}
interface ChildNoBaseClass extends BaseInterface {
>ChildNoBaseClass : Symbol(ChildNoBaseClass, Decl(mergedInheritedClassInterface.ts, 17, 1), Decl(mergedInheritedClassInterface.ts, 21, 1))
>BaseInterface : Symbol(BaseInterface, Decl(mergedInheritedClassInterface.ts, 0, 0))
additional2: string;
>additional2 : Symbol(additional2, Decl(mergedInheritedClassInterface.ts, 19, 50))
}
class ChildNoBaseClass {
>ChildNoBaseClass : Symbol(ChildNoBaseClass, Decl(mergedInheritedClassInterface.ts, 17, 1), Decl(mergedInheritedClassInterface.ts, 21, 1))
classString: string;
>classString : Symbol(classString, Decl(mergedInheritedClassInterface.ts, 22, 24))
method2() { }
>method2 : Symbol(method2, Decl(mergedInheritedClassInterface.ts, 23, 24))
}
class Grandchild extends ChildNoBaseClass {
>Grandchild : Symbol(Grandchild, Decl(mergedInheritedClassInterface.ts, 25, 1))
>ChildNoBaseClass : Symbol(ChildNoBaseClass, Decl(mergedInheritedClassInterface.ts, 17, 1), Decl(mergedInheritedClassInterface.ts, 21, 1))
}
// checks if properties actually were merged
var child : Child;
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>Child : Symbol(Child, Decl(mergedInheritedClassInterface.ts, 8, 1), Decl(mergedInheritedClassInterface.ts, 12, 1))
child.required;
>child.required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
child.optional;
>child.optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
child.additional;
>child.additional : Symbol(Child.additional, Decl(mergedInheritedClassInterface.ts, 10, 39))
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>additional : Symbol(Child.additional, Decl(mergedInheritedClassInterface.ts, 10, 39))
child.baseNumber;
>child.baseNumber : Symbol(BaseClass.baseNumber, Decl(mergedInheritedClassInterface.ts, 6, 20))
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>baseNumber : Symbol(BaseClass.baseNumber, Decl(mergedInheritedClassInterface.ts, 6, 20))
child.classNumber;
>child.classNumber : Symbol(Child.classNumber, Decl(mergedInheritedClassInterface.ts, 14, 31))
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>classNumber : Symbol(Child.classNumber, Decl(mergedInheritedClassInterface.ts, 14, 31))
child.baseMethod();
>child.baseMethod : Symbol(BaseClass.baseMethod, Decl(mergedInheritedClassInterface.ts, 5, 17))
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>baseMethod : Symbol(BaseClass.baseMethod, Decl(mergedInheritedClassInterface.ts, 5, 17))
child.method();
>child.method : Symbol(Child.method, Decl(mergedInheritedClassInterface.ts, 15, 24))
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
>method : Symbol(Child.method, Decl(mergedInheritedClassInterface.ts, 15, 24))
var grandchild: Grandchild;
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
>Grandchild : Symbol(Grandchild, Decl(mergedInheritedClassInterface.ts, 25, 1))
grandchild.required;
>grandchild.required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
>required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
grandchild.optional;
>grandchild.optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
>optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
grandchild.additional2;
>grandchild.additional2 : Symbol(ChildNoBaseClass.additional2, Decl(mergedInheritedClassInterface.ts, 19, 50))
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
>additional2 : Symbol(ChildNoBaseClass.additional2, Decl(mergedInheritedClassInterface.ts, 19, 50))
grandchild.classString;
>grandchild.classString : Symbol(ChildNoBaseClass.classString, Decl(mergedInheritedClassInterface.ts, 22, 24))
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
>classString : Symbol(ChildNoBaseClass.classString, Decl(mergedInheritedClassInterface.ts, 22, 24))
grandchild.method2();
>grandchild.method2 : Symbol(ChildNoBaseClass.method2, Decl(mergedInheritedClassInterface.ts, 23, 24))
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
>method2 : Symbol(ChildNoBaseClass.method2, Decl(mergedInheritedClassInterface.ts, 23, 24))

View File

@ -0,0 +1,133 @@
=== tests/cases/conformance/classes/classDeclarations/mergedInheritedClassInterface.ts ===
interface BaseInterface {
>BaseInterface : BaseInterface
required: number;
>required : number
optional?: number;
>optional : number
}
class BaseClass {
>BaseClass : BaseClass
baseMethod() { }
>baseMethod : () => void
baseNumber: number;
>baseNumber : number
}
interface Child extends BaseInterface {
>Child : Child
>BaseInterface : BaseInterface
additional: number;
>additional : number
}
class Child extends BaseClass {
>Child : Child
>BaseClass : BaseClass
classNumber: number;
>classNumber : number
method() { }
>method : () => void
}
interface ChildNoBaseClass extends BaseInterface {
>ChildNoBaseClass : ChildNoBaseClass
>BaseInterface : BaseInterface
additional2: string;
>additional2 : string
}
class ChildNoBaseClass {
>ChildNoBaseClass : ChildNoBaseClass
classString: string;
>classString : string
method2() { }
>method2 : () => void
}
class Grandchild extends ChildNoBaseClass {
>Grandchild : Grandchild
>ChildNoBaseClass : ChildNoBaseClass
}
// checks if properties actually were merged
var child : Child;
>child : Child
>Child : Child
child.required;
>child.required : number
>child : Child
>required : number
child.optional;
>child.optional : number
>child : Child
>optional : number
child.additional;
>child.additional : number
>child : Child
>additional : number
child.baseNumber;
>child.baseNumber : number
>child : Child
>baseNumber : number
child.classNumber;
>child.classNumber : number
>child : Child
>classNumber : number
child.baseMethod();
>child.baseMethod() : void
>child.baseMethod : () => void
>child : Child
>baseMethod : () => void
child.method();
>child.method() : void
>child.method : () => void
>child : Child
>method : () => void
var grandchild: Grandchild;
>grandchild : Grandchild
>Grandchild : Grandchild
grandchild.required;
>grandchild.required : number
>grandchild : Grandchild
>required : number
grandchild.optional;
>grandchild.optional : number
>grandchild : Grandchild
>optional : number
grandchild.additional2;
>grandchild.additional2 : string
>grandchild : Grandchild
>additional2 : string
grandchild.classString;
>grandchild.classString : string
>grandchild : Grandchild
>classString : string
grandchild.method2();
>grandchild.method2() : void
>grandchild.method2 : () => void
>grandchild : Grandchild
>method2 : () => void

View File

@ -1,5 +1,5 @@
tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(8,3): error TS2345: Argument of type '{}' is not assignable to parameter of type 'TemplateStringsArray'.
Property 'raw' is missing in type '{}'.
tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(8,3): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
Property 'raw' is missing in type '{ [x: number]: undefined; }'.
==== tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts (1 errors) ====
@ -12,7 +12,7 @@ tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(8,3): error TS2
f({}, 10, 10);
~~
!!! error TS2345: Argument of type '{}' is not assignable to parameter of type 'TemplateStringsArray'.
!!! error TS2345: Property 'raw' is missing in type '{}'.
!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
!!! error TS2345: Property 'raw' is missing in type '{ [x: number]: undefined; }'.
f `abcdef${ 1234 }${ 5678 }ghijkl`;

View File

@ -1,5 +1,5 @@
tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts(8,3): error TS2345: Argument of type '{}' is not assignable to parameter of type 'TemplateStringsArray'.
Property 'raw' is missing in type '{}'.
tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts(8,3): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
Property 'raw' is missing in type '{ [x: number]: undefined; }'.
==== tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts (1 errors) ====
@ -12,7 +12,7 @@ tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts(8,3): error T
f({}, 10, 10);
~~
!!! error TS2345: Argument of type '{}' is not assignable to parameter of type 'TemplateStringsArray'.
!!! error TS2345: Property 'raw' is missing in type '{}'.
!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
!!! error TS2345: Property 'raw' is missing in type '{ [x: number]: undefined; }'.
f `abcdef${ 1234 }${ 5678 }ghijkl`;

View File

@ -0,0 +1,45 @@
interface BaseInterface {
required: number;
optional?: number;
}
class BaseClass {
baseMethod() { }
baseNumber: number;
}
interface Child extends BaseInterface {
additional: number;
}
class Child extends BaseClass {
classNumber: number;
method() { }
}
interface ChildNoBaseClass extends BaseInterface {
additional2: string;
}
class ChildNoBaseClass {
classString: string;
method2() { }
}
class Grandchild extends ChildNoBaseClass {
}
// checks if properties actually were merged
var child : Child;
child.required;
child.optional;
child.additional;
child.baseNumber;
child.classNumber;
child.baseMethod();
child.method();
var grandchild: Grandchild;
grandchild.required;
grandchild.optional;
grandchild.additional2;
grandchild.classString;
grandchild.method2();