From 80453021af8a22ed69b151ced0c4a68bdf1ed832 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 3 Dec 2015 14:01:20 -0800 Subject: [PATCH 1/5] Inherit construct signature for extended interface --- src/compiler/checker.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e737cd58bd5..05041dcaeed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2938,8 +2938,8 @@ namespace ts { return type.resolvedBaseConstructorType; } - function hasClassBaseType(type: InterfaceType): boolean { - return !!forEach(getBaseTypes(type), t => !!(t.symbol.flags & SymbolFlags.Class)); + function hasClassOrInterfaceBaseType(type: InterfaceType): boolean { + return !!forEach(getBaseTypes(type), t => !!(t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface))); } function getBaseTypes(type: InterfaceType): ObjectType[] { @@ -3375,11 +3375,14 @@ namespace ts { } function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { - if (!hasClassBaseType(classType)) { + if (!hasClassOrInterfaceBaseType(classType)) { return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; } const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); + if(baseSignatures.length === 0) { + return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; + } const baseTypeNode = getBaseTypeNodeOfClass(classType); const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode); const typeArgCount = typeArguments ? typeArguments.length : 0; @@ -3597,7 +3600,8 @@ namespace ts { return type; } - // Return properties of an object type or an empty array for other types + + /** Return properties of an object type or an empty array for other types */ function getPropertiesOfObjectType(type: Type): Symbol[] { if (type.flags & TypeFlags.ObjectType) { return resolveStructuredTypeMembers(type).properties; @@ -3605,8 +3609,8 @@ namespace ts { return emptyArray; } - // If the given type is an object type and that type has a property by the given name, - // return the symbol for that property.Otherwise return undefined. + /** If the given type is an object type and that type has a property by the given name, + * return the symbol for that property. Otherwise return undefined. */ function getPropertyOfObjectType(type: Type, name: string): Symbol { if (type.flags & TypeFlags.ObjectType) { const resolved = resolveStructuredTypeMembers(type); From ae559a7ccf06993d849e0e34e20c5d2efed2e763 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 3 Dec 2015 15:51:15 -0800 Subject: [PATCH 2/5] Add test and accept baselines --- .../extendConstructSignatureInInterface.js | 27 +++++++++++++++++++ ...xtendConstructSignatureInInterface.symbols | 23 ++++++++++++++++ .../extendConstructSignatureInInterface.types | 25 +++++++++++++++++ .../extendConstructSignatureInInterface.ts | 9 +++++++ 4 files changed, 84 insertions(+) create mode 100644 tests/baselines/reference/extendConstructSignatureInInterface.js create mode 100644 tests/baselines/reference/extendConstructSignatureInInterface.symbols create mode 100644 tests/baselines/reference/extendConstructSignatureInInterface.types create mode 100644 tests/cases/compiler/extendConstructSignatureInInterface.ts diff --git a/tests/baselines/reference/extendConstructSignatureInInterface.js b/tests/baselines/reference/extendConstructSignatureInInterface.js new file mode 100644 index 00000000000..c440872a566 --- /dev/null +++ b/tests/baselines/reference/extendConstructSignatureInInterface.js @@ -0,0 +1,27 @@ +//// [extendConstructSignatureInInterface.ts] +interface C { + new(x: number): C; +} + +var CStatic: C; +class E extends CStatic { +} + +var e: E = new E(1); + + +//// [extendConstructSignatureInInterface.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 CStatic; +var E = (function (_super) { + __extends(E, _super); + function E() { + _super.apply(this, arguments); + } + return E; +})(CStatic); +var e = new E(1); diff --git a/tests/baselines/reference/extendConstructSignatureInInterface.symbols b/tests/baselines/reference/extendConstructSignatureInInterface.symbols new file mode 100644 index 00000000000..df966bc9fcc --- /dev/null +++ b/tests/baselines/reference/extendConstructSignatureInInterface.symbols @@ -0,0 +1,23 @@ +=== tests/cases/compiler/extendConstructSignatureInInterface.ts === +interface C { +>C : Symbol(C, Decl(extendConstructSignatureInInterface.ts, 0, 0)) + + new(x: number): C; +>x : Symbol(x, Decl(extendConstructSignatureInInterface.ts, 1, 8)) +>C : Symbol(C, Decl(extendConstructSignatureInInterface.ts, 0, 0)) +} + +var CStatic: C; +>CStatic : Symbol(CStatic, Decl(extendConstructSignatureInInterface.ts, 4, 3)) +>C : Symbol(C, Decl(extendConstructSignatureInInterface.ts, 0, 0)) + +class E extends CStatic { +>E : Symbol(E, Decl(extendConstructSignatureInInterface.ts, 4, 15)) +>CStatic : Symbol(CStatic, Decl(extendConstructSignatureInInterface.ts, 4, 3)) +} + +var e: E = new E(1); +>e : Symbol(e, Decl(extendConstructSignatureInInterface.ts, 8, 3)) +>E : Symbol(E, Decl(extendConstructSignatureInInterface.ts, 4, 15)) +>E : Symbol(E, Decl(extendConstructSignatureInInterface.ts, 4, 15)) + diff --git a/tests/baselines/reference/extendConstructSignatureInInterface.types b/tests/baselines/reference/extendConstructSignatureInInterface.types new file mode 100644 index 00000000000..363107b2e54 --- /dev/null +++ b/tests/baselines/reference/extendConstructSignatureInInterface.types @@ -0,0 +1,25 @@ +=== tests/cases/compiler/extendConstructSignatureInInterface.ts === +interface C { +>C : C + + new(x: number): C; +>x : number +>C : C +} + +var CStatic: C; +>CStatic : C +>C : C + +class E extends CStatic { +>E : E +>CStatic : C +} + +var e: E = new E(1); +>e : E +>E : E +>new E(1) : E +>E : typeof E +>1 : number + diff --git a/tests/cases/compiler/extendConstructSignatureInInterface.ts b/tests/cases/compiler/extendConstructSignatureInInterface.ts new file mode 100644 index 00000000000..a0880de69cd --- /dev/null +++ b/tests/cases/compiler/extendConstructSignatureInInterface.ts @@ -0,0 +1,9 @@ +interface C { + new(x: number): C; +} + +var CStatic: C; +class E extends CStatic { +} + +var e: E = new E(1); From b8af5248b56c7be37191317da0d16e059f49b820 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Dec 2015 09:00:04 -0800 Subject: [PATCH 3/5] Simplify check for constructors --- src/compiler/checker.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 05041dcaeed..eef82b1032a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2938,10 +2938,6 @@ namespace ts { return type.resolvedBaseConstructorType; } - function hasClassOrInterfaceBaseType(type: InterfaceType): boolean { - return !!forEach(getBaseTypes(type), t => !!(t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface))); - } - function getBaseTypes(type: InterfaceType): ObjectType[] { const isClass = type.symbol.flags & SymbolFlags.Class; const isInterface = type.symbol.flags & SymbolFlags.Interface; @@ -3375,9 +3371,6 @@ namespace ts { } function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { - if (!hasClassOrInterfaceBaseType(classType)) { - return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; - } const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); if(baseSignatures.length === 0) { From c94d5347488a80297e68f4c3e2578de1ccd6079a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Dec 2015 09:00:32 -0800 Subject: [PATCH 4/5] Accept new baseline In recursiveBaseConstructorCreator3, the error message has improved to match the originally intended error. --- .../recursiveBaseConstructorCreation3.errors.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/recursiveBaseConstructorCreation3.errors.txt b/tests/baselines/reference/recursiveBaseConstructorCreation3.errors.txt index b8429be5ea0..bd392492899 100644 --- a/tests/baselines/reference/recursiveBaseConstructorCreation3.errors.txt +++ b/tests/baselines/reference/recursiveBaseConstructorCreation3.errors.txt @@ -1,5 +1,5 @@ tests/cases/compiler/recursiveBaseConstructorCreation3.ts(6,27): error TS2314: Generic type 'abc' requires 1 type argument(s). -tests/cases/compiler/recursiveBaseConstructorCreation3.ts(10,18): error TS2339: Property 'foo' does not exist on type 'xyz'. +tests/cases/compiler/recursiveBaseConstructorCreation3.ts(9,11): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. ==== tests/cases/compiler/recursiveBaseConstructorCreation3.ts (2 errors) ==== @@ -14,6 +14,6 @@ tests/cases/compiler/recursiveBaseConstructorCreation3.ts(10,18): error TS2339: } var bar = new xyz(); // Error: Invalid 'new' expression. - var r: xyz = bar.foo; - ~~~ -!!! error TS2339: Property 'foo' does not exist on type 'xyz'. \ No newline at end of file + ~~~~~~~~~ +!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. + var r: xyz = bar.foo; \ No newline at end of file From e2b6898018d66d86262a56a2c4379ecd4b565884 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Dec 2015 09:07:32 -0800 Subject: [PATCH 5/5] remove lint --- src/compiler/checker.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eef82b1032a..402786dc6ab 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3373,7 +3373,7 @@ namespace ts { function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); - if(baseSignatures.length === 0) { + if (baseSignatures.length === 0) { return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; } const baseTypeNode = getBaseTypeNodeOfClass(classType); @@ -3593,7 +3593,6 @@ namespace ts { return type; } - /** Return properties of an object type or an empty array for other types */ function getPropertiesOfObjectType(type: Type): Symbol[] { if (type.flags & TypeFlags.ObjectType) {