diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4d1f0ad315b..46e6dcb1138 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17594,6 +17594,11 @@ namespace ts { error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); } } + if (type.flags & TypeFlags.TypeParameter && !(type).isThisType && type.symbol) { + if (!isTypeParameterInScope(type, node)) { + error(node.name, Diagnostics.Type_parameter_0_cannot_be_referenced_outside_of_a_declaration_that_defines_it, symbolToString(type.symbol)); + } + } if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) { // We know we don't have a binding pattern or computed name here checkExportsOnMergedDeclarations(node); @@ -17608,6 +17613,19 @@ namespace ts { } } + function isTypeParameterInScope(typeParameter: TypeParameter, node: Node) { + const parents = map(filter(typeParameter.symbol.declarations, isTypeParameter), node => node.parent); + while (node) { + if (isFunctionLike(node) || isClassLike(node) || node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.TypeAliasDeclaration) { + if (contains(parents, node)) { + return true; + } + } + node = node.parent; + } + return false; + } + function areDeclarationFlagsIdentical(left: Declaration, right: Declaration) { if ((left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) || (left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter)) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 062663f3ba8..ca4162804d0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1127,6 +1127,10 @@ "category": "Error", "code": 2366 }, + "Type parameter '{0}' cannot be referenced outside of a declaration that defines it.": { + "category": "Error", + "code": 2367 + }, "Type parameter name cannot be '{0}'": { "category": "Error", "code": 2368 diff --git a/tests/baselines/reference/genericDefaultsErrors.errors.txt b/tests/baselines/reference/genericDefaultsErrors.errors.txt index a21fcec1142..ab2eb71e0ea 100644 --- a/tests/baselines/reference/genericDefaultsErrors.errors.txt +++ b/tests/baselines/reference/genericDefaultsErrors.errors.txt @@ -31,9 +31,10 @@ tests/cases/compiler/genericDefaultsErrors.ts(35,32): error TS2344: Type 'number tests/cases/compiler/genericDefaultsErrors.ts(38,15): error TS2707: Generic type 'i09' requires between 2 and 3 type arguments. tests/cases/compiler/genericDefaultsErrors.ts(39,15): error TS2707: Generic type 'i09' requires between 2 and 3 type arguments. tests/cases/compiler/genericDefaultsErrors.ts(42,15): error TS2707: Generic type 'i09' requires between 2 and 3 type arguments. +tests/cases/compiler/genericDefaultsErrors.ts(44,17): error TS2367: Type parameter 'T' cannot be referenced outside of a declaration that defines it. -==== tests/cases/compiler/genericDefaultsErrors.ts (31 errors) ==== +==== tests/cases/compiler/genericDefaultsErrors.ts (32 errors) ==== declare const x: any; @@ -139,4 +140,9 @@ tests/cases/compiler/genericDefaultsErrors.ts(42,15): error TS2707: Generic type type i09t03 = i09<1, 2, 3>; // ok type i09t04 = i09<1, 2, 3, 4>; // error ~~~~~~~~~~~~~~~ -!!! error TS2707: Generic type 'i09' requires between 2 and 3 type arguments. \ No newline at end of file +!!! error TS2707: Generic type 'i09' requires between 2 and 3 type arguments. + + interface i10 { x: T; } // error + ~ +!!! error TS2367: Type parameter 'T' cannot be referenced outside of a declaration that defines it. + interface i10 {} \ No newline at end of file diff --git a/tests/baselines/reference/genericDefaultsErrors.js b/tests/baselines/reference/genericDefaultsErrors.js index dc0670d5272..12bac1a8ff4 100644 --- a/tests/baselines/reference/genericDefaultsErrors.js +++ b/tests/baselines/reference/genericDefaultsErrors.js @@ -40,7 +40,10 @@ type i09t00 = i09; // error type i09t01 = i09<1>; // error type i09t02 = i09<1, 2>; // ok type i09t03 = i09<1, 2, 3>; // ok -type i09t04 = i09<1, 2, 3, 4>; // error +type i09t04 = i09<1, 2, 3, 4>; // error + +interface i10 { x: T; } // error +interface i10 {} //// [genericDefaultsErrors.js] f11(); // ok @@ -101,3 +104,8 @@ declare type i09t01 = i09<1>; declare type i09t02 = i09<1, 2>; declare type i09t03 = i09<1, 2, 3>; declare type i09t04 = i09<1, 2, 3, 4>; +interface i10 { + x: T; +} +interface i10 { +} diff --git a/tests/cases/compiler/genericDefaultsErrors.ts b/tests/cases/compiler/genericDefaultsErrors.ts index 985300f6607..0e3cf3003b1 100644 --- a/tests/cases/compiler/genericDefaultsErrors.ts +++ b/tests/cases/compiler/genericDefaultsErrors.ts @@ -40,4 +40,7 @@ type i09t00 = i09; // error type i09t01 = i09<1>; // error type i09t02 = i09<1, 2>; // ok type i09t03 = i09<1, 2, 3>; // ok -type i09t04 = i09<1, 2, 3, 4>; // error \ No newline at end of file +type i09t04 = i09<1, 2, 3, 4>; // error + +interface i10 { x: T; } // error +interface i10 {} \ No newline at end of file