From bb2eb635d60c7b63da580e130beacea386b28507 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 19 Feb 2016 11:36:35 -0800 Subject: [PATCH] Merged classes and interfaces must have identical type constraints Previously, only interfaces needed to check this, but now that classes and interfaces can merge, the check needs to happen in more places. --- src/compiler/checker.ts | 28 +++++++++++++++++++++------- src/compiler/diagnosticMessages.json | 4 ++-- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eddddb5cb2b..b9a8ab6cd2c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14013,7 +14013,7 @@ namespace ts { } } - // Check each type parameter and check that list has no duplicate type parameter declarations + /** Check each type parameter and check that type parameters have no duplicate type parameter declarations */ function checkTypeParameters(typeParameterDeclarations: TypeParameterDeclaration[]) { if (typeParameterDeclarations) { for (let i = 0, n = typeParameterDeclarations.length; i < n; i++) { @@ -14031,6 +14031,23 @@ namespace ts { } } + /** Check that type parameter lists are identical across multiple declarations */ + function checkTypeParameterListsIdentical(node: ClassLikeDeclaration | InterfaceDeclaration, symbol: Symbol) { + let firstDecl: ClassLikeDeclaration | InterfaceDeclaration; + if (symbol.declarations.length > 1) { + for (const declaration of symbol.declarations) { + if (declaration.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.InterfaceDeclaration) { + if (!firstDecl) { + firstDecl = declaration; + } + else if (!areTypeParametersIdentical(firstDecl.typeParameters, node.typeParameters)) { + error(node.name, Diagnostics.All_declarations_must_have_identical_type_parameters); + } + } + } + } + } + function checkClassExpression(node: ClassExpression): Type { checkClassLikeDeclaration(node); checkNodeDeferred(node); @@ -14064,6 +14081,7 @@ namespace ts { const type = getDeclaredTypeOfSymbol(symbol); const typeWithThis = getTypeWithThisArgument(type); const staticType = getTypeOfSymbol(symbol); + checkTypeParameterListsIdentical(node, symbol); const baseTypeNode = getClassExtendsHeritageClauseElement(node); if (baseTypeNode) { @@ -14326,14 +14344,10 @@ namespace ts { checkExportsOnMergedDeclarations(node); const symbol = getSymbolOfNode(node); - const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); - if (symbol.declarations.length > 1) { - if (node !== firstInterfaceDecl && !areTypeParametersIdentical(firstInterfaceDecl.typeParameters, node.typeParameters)) { - error(node.name, Diagnostics.All_declarations_of_an_interface_must_have_identical_type_parameters); - } - } + checkTypeParameterListsIdentical(node, symbol); // Only check this symbol once + const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); if (node === firstInterfaceDecl) { const type = getDeclaredTypeOfSymbol(symbol); const typeWithThis = getTypeWithThisArgument(type); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 16cf1911642..92396d005b7 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1311,7 +1311,7 @@ "category": "Error", "code": 2427 }, - "All declarations of an interface must have identical type parameters.": { + "All declarations must have identical type parameters.": { "category": "Error", "code": 2428 }, @@ -2801,4 +2801,4 @@ "category": "Error", "code": 17009 } -} +}