Skip to content

Commit d26a4c8

Browse files
committed
Merge pull request #5359 from Microsoft/merge-inherits-interface-members
Merge inherits interface members
2 parents 69986a1 + 742c701 commit d26a4c8

File tree

7 files changed

+438
-18
lines changed

7 files changed

+438
-18
lines changed

src/compiler/checker.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2845,23 +2845,29 @@ namespace ts {
28452845
return type.resolvedBaseConstructorType;
28462846
}
28472847

2848+
function hasClassBaseType(type: InterfaceType): boolean {
2849+
return !!forEach(getBaseTypes(type), t => !!(t.symbol.flags & SymbolFlags.Class));
2850+
}
2851+
28482852
function getBaseTypes(type: InterfaceType): ObjectType[] {
2853+
let isClass = type.symbol.flags & SymbolFlags.Class;
2854+
let isInterface = type.symbol.flags & SymbolFlags.Interface;
28492855
if (!type.resolvedBaseTypes) {
2850-
if (type.symbol.flags & SymbolFlags.Class) {
2856+
if (!isClass && !isInterface) {
2857+
Debug.fail("type must be class or interface");
2858+
}
2859+
if (isClass) {
28512860
resolveBaseTypesOfClass(type);
28522861
}
2853-
else if (type.symbol.flags & SymbolFlags.Interface) {
2862+
if (isInterface) {
28542863
resolveBaseTypesOfInterface(type);
28552864
}
2856-
else {
2857-
Debug.fail("type must be class or interface");
2858-
}
28592865
}
28602866
return type.resolvedBaseTypes;
28612867
}
28622868

28632869
function resolveBaseTypesOfClass(type: InterfaceType): void {
2864-
type.resolvedBaseTypes = emptyArray;
2870+
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
28652871
let baseContructorType = getBaseConstructorTypeOfClass(type);
28662872
if (!(baseContructorType.flags & TypeFlags.ObjectType)) {
28672873
return;
@@ -2897,19 +2903,29 @@ namespace ts {
28972903
typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
28982904
return;
28992905
}
2900-
type.resolvedBaseTypes = [baseType];
2906+
if (type.resolvedBaseTypes === emptyArray) {
2907+
type.resolvedBaseTypes = [baseType];
2908+
}
2909+
else {
2910+
type.resolvedBaseTypes.push(baseType);
2911+
}
29012912
}
29022913

29032914
function resolveBaseTypesOfInterface(type: InterfaceType): void {
2904-
type.resolvedBaseTypes = [];
2915+
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
29052916
for (let declaration of type.symbol.declarations) {
29062917
if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(<InterfaceDeclaration>declaration)) {
29072918
for (let node of getInterfaceBaseTypeNodes(<InterfaceDeclaration>declaration)) {
29082919
let baseType = getTypeFromTypeNode(node);
29092920
if (baseType !== unknownType) {
29102921
if (getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface)) {
29112922
if (type !== baseType && !hasBaseType(<InterfaceType>baseType, type)) {
2912-
type.resolvedBaseTypes.push(baseType);
2923+
if (type.resolvedBaseTypes === emptyArray) {
2924+
type.resolvedBaseTypes = [baseType];
2925+
}
2926+
else {
2927+
type.resolvedBaseTypes.push(baseType);
2928+
}
29132929
}
29142930
else {
29152931
error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
@@ -3252,7 +3268,7 @@ namespace ts {
32523268
}
32533269

32543270
function getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
3255-
if (!getBaseTypes(classType).length) {
3271+
if (!hasClassBaseType(classType)) {
32563272
return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, false, false)];
32573273
}
32583274
let baseConstructorType = getBaseConstructorTypeOfClass(classType);
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//// [mergedInheritedClassInterface.ts]
2+
interface BaseInterface {
3+
required: number;
4+
optional?: number;
5+
}
6+
7+
class BaseClass {
8+
baseMethod() { }
9+
baseNumber: number;
10+
}
11+
12+
interface Child extends BaseInterface {
13+
additional: number;
14+
}
15+
16+
class Child extends BaseClass {
17+
classNumber: number;
18+
method() { }
19+
}
20+
21+
interface ChildNoBaseClass extends BaseInterface {
22+
additional2: string;
23+
}
24+
class ChildNoBaseClass {
25+
classString: string;
26+
method2() { }
27+
}
28+
class Grandchild extends ChildNoBaseClass {
29+
}
30+
31+
// checks if properties actually were merged
32+
var child : Child;
33+
child.required;
34+
child.optional;
35+
child.additional;
36+
child.baseNumber;
37+
child.classNumber;
38+
child.baseMethod();
39+
child.method();
40+
41+
var grandchild: Grandchild;
42+
grandchild.required;
43+
grandchild.optional;
44+
grandchild.additional2;
45+
grandchild.classString;
46+
grandchild.method2();
47+
48+
49+
//// [mergedInheritedClassInterface.js]
50+
var __extends = (this && this.__extends) || function (d, b) {
51+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
52+
function __() { this.constructor = d; }
53+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
54+
};
55+
var BaseClass = (function () {
56+
function BaseClass() {
57+
}
58+
BaseClass.prototype.baseMethod = function () { };
59+
return BaseClass;
60+
})();
61+
var Child = (function (_super) {
62+
__extends(Child, _super);
63+
function Child() {
64+
_super.apply(this, arguments);
65+
}
66+
Child.prototype.method = function () { };
67+
return Child;
68+
})(BaseClass);
69+
var ChildNoBaseClass = (function () {
70+
function ChildNoBaseClass() {
71+
}
72+
ChildNoBaseClass.prototype.method2 = function () { };
73+
return ChildNoBaseClass;
74+
})();
75+
var Grandchild = (function (_super) {
76+
__extends(Grandchild, _super);
77+
function Grandchild() {
78+
_super.apply(this, arguments);
79+
}
80+
return Grandchild;
81+
})(ChildNoBaseClass);
82+
// checks if properties actually were merged
83+
var child;
84+
child.required;
85+
child.optional;
86+
child.additional;
87+
child.baseNumber;
88+
child.classNumber;
89+
child.baseMethod();
90+
child.method();
91+
var grandchild;
92+
grandchild.required;
93+
grandchild.optional;
94+
grandchild.additional2;
95+
grandchild.classString;
96+
grandchild.method2();
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
=== tests/cases/conformance/classes/classDeclarations/mergedInheritedClassInterface.ts ===
2+
interface BaseInterface {
3+
>BaseInterface : Symbol(BaseInterface, Decl(mergedInheritedClassInterface.ts, 0, 0))
4+
5+
required: number;
6+
>required : Symbol(required, Decl(mergedInheritedClassInterface.ts, 0, 25))
7+
8+
optional?: number;
9+
>optional : Symbol(optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
10+
}
11+
12+
class BaseClass {
13+
>BaseClass : Symbol(BaseClass, Decl(mergedInheritedClassInterface.ts, 3, 1))
14+
15+
baseMethod() { }
16+
>baseMethod : Symbol(baseMethod, Decl(mergedInheritedClassInterface.ts, 5, 17))
17+
18+
baseNumber: number;
19+
>baseNumber : Symbol(baseNumber, Decl(mergedInheritedClassInterface.ts, 6, 20))
20+
}
21+
22+
interface Child extends BaseInterface {
23+
>Child : Symbol(Child, Decl(mergedInheritedClassInterface.ts, 8, 1), Decl(mergedInheritedClassInterface.ts, 12, 1))
24+
>BaseInterface : Symbol(BaseInterface, Decl(mergedInheritedClassInterface.ts, 0, 0))
25+
26+
additional: number;
27+
>additional : Symbol(additional, Decl(mergedInheritedClassInterface.ts, 10, 39))
28+
}
29+
30+
class Child extends BaseClass {
31+
>Child : Symbol(Child, Decl(mergedInheritedClassInterface.ts, 8, 1), Decl(mergedInheritedClassInterface.ts, 12, 1))
32+
>BaseClass : Symbol(BaseClass, Decl(mergedInheritedClassInterface.ts, 3, 1))
33+
34+
classNumber: number;
35+
>classNumber : Symbol(classNumber, Decl(mergedInheritedClassInterface.ts, 14, 31))
36+
37+
method() { }
38+
>method : Symbol(method, Decl(mergedInheritedClassInterface.ts, 15, 24))
39+
}
40+
41+
interface ChildNoBaseClass extends BaseInterface {
42+
>ChildNoBaseClass : Symbol(ChildNoBaseClass, Decl(mergedInheritedClassInterface.ts, 17, 1), Decl(mergedInheritedClassInterface.ts, 21, 1))
43+
>BaseInterface : Symbol(BaseInterface, Decl(mergedInheritedClassInterface.ts, 0, 0))
44+
45+
additional2: string;
46+
>additional2 : Symbol(additional2, Decl(mergedInheritedClassInterface.ts, 19, 50))
47+
}
48+
class ChildNoBaseClass {
49+
>ChildNoBaseClass : Symbol(ChildNoBaseClass, Decl(mergedInheritedClassInterface.ts, 17, 1), Decl(mergedInheritedClassInterface.ts, 21, 1))
50+
51+
classString: string;
52+
>classString : Symbol(classString, Decl(mergedInheritedClassInterface.ts, 22, 24))
53+
54+
method2() { }
55+
>method2 : Symbol(method2, Decl(mergedInheritedClassInterface.ts, 23, 24))
56+
}
57+
class Grandchild extends ChildNoBaseClass {
58+
>Grandchild : Symbol(Grandchild, Decl(mergedInheritedClassInterface.ts, 25, 1))
59+
>ChildNoBaseClass : Symbol(ChildNoBaseClass, Decl(mergedInheritedClassInterface.ts, 17, 1), Decl(mergedInheritedClassInterface.ts, 21, 1))
60+
}
61+
62+
// checks if properties actually were merged
63+
var child : Child;
64+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
65+
>Child : Symbol(Child, Decl(mergedInheritedClassInterface.ts, 8, 1), Decl(mergedInheritedClassInterface.ts, 12, 1))
66+
67+
child.required;
68+
>child.required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
69+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
70+
>required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
71+
72+
child.optional;
73+
>child.optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
74+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
75+
>optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
76+
77+
child.additional;
78+
>child.additional : Symbol(Child.additional, Decl(mergedInheritedClassInterface.ts, 10, 39))
79+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
80+
>additional : Symbol(Child.additional, Decl(mergedInheritedClassInterface.ts, 10, 39))
81+
82+
child.baseNumber;
83+
>child.baseNumber : Symbol(BaseClass.baseNumber, Decl(mergedInheritedClassInterface.ts, 6, 20))
84+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
85+
>baseNumber : Symbol(BaseClass.baseNumber, Decl(mergedInheritedClassInterface.ts, 6, 20))
86+
87+
child.classNumber;
88+
>child.classNumber : Symbol(Child.classNumber, Decl(mergedInheritedClassInterface.ts, 14, 31))
89+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
90+
>classNumber : Symbol(Child.classNumber, Decl(mergedInheritedClassInterface.ts, 14, 31))
91+
92+
child.baseMethod();
93+
>child.baseMethod : Symbol(BaseClass.baseMethod, Decl(mergedInheritedClassInterface.ts, 5, 17))
94+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
95+
>baseMethod : Symbol(BaseClass.baseMethod, Decl(mergedInheritedClassInterface.ts, 5, 17))
96+
97+
child.method();
98+
>child.method : Symbol(Child.method, Decl(mergedInheritedClassInterface.ts, 15, 24))
99+
>child : Symbol(child, Decl(mergedInheritedClassInterface.ts, 30, 3))
100+
>method : Symbol(Child.method, Decl(mergedInheritedClassInterface.ts, 15, 24))
101+
102+
var grandchild: Grandchild;
103+
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
104+
>Grandchild : Symbol(Grandchild, Decl(mergedInheritedClassInterface.ts, 25, 1))
105+
106+
grandchild.required;
107+
>grandchild.required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
108+
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
109+
>required : Symbol(BaseInterface.required, Decl(mergedInheritedClassInterface.ts, 0, 25))
110+
111+
grandchild.optional;
112+
>grandchild.optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
113+
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
114+
>optional : Symbol(BaseInterface.optional, Decl(mergedInheritedClassInterface.ts, 1, 21))
115+
116+
grandchild.additional2;
117+
>grandchild.additional2 : Symbol(ChildNoBaseClass.additional2, Decl(mergedInheritedClassInterface.ts, 19, 50))
118+
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
119+
>additional2 : Symbol(ChildNoBaseClass.additional2, Decl(mergedInheritedClassInterface.ts, 19, 50))
120+
121+
grandchild.classString;
122+
>grandchild.classString : Symbol(ChildNoBaseClass.classString, Decl(mergedInheritedClassInterface.ts, 22, 24))
123+
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
124+
>classString : Symbol(ChildNoBaseClass.classString, Decl(mergedInheritedClassInterface.ts, 22, 24))
125+
126+
grandchild.method2();
127+
>grandchild.method2 : Symbol(ChildNoBaseClass.method2, Decl(mergedInheritedClassInterface.ts, 23, 24))
128+
>grandchild : Symbol(grandchild, Decl(mergedInheritedClassInterface.ts, 39, 3))
129+
>method2 : Symbol(ChildNoBaseClass.method2, Decl(mergedInheritedClassInterface.ts, 23, 24))
130+

0 commit comments

Comments
 (0)