diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a2e0c490642..4a06ff23c95 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25781,6 +25781,10 @@ namespace ts { return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_cannot_be_a_type_alias_Use_index_Colon_0_instead, typeToString(type)); } + if (type.flags & TypeFlags.Union && forEach((type).types, t => !!(t.flags & TypeFlags.StringOrNumberLiteral))) { + return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_cannot_be_a_union_type_Use_K_in_0_instead, symbolName(type.aliasSymbol)); + } + return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_or_number); } if (!node.type) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 083396e51d2..9ff6a591a02 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -943,6 +943,10 @@ "category": "Error", "code": 1336 }, + "An index signature parameter type cannot be a union type. Use '[K in {0}]' instead.": { + "category": "Error", + "code": 1337 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/tests/baselines/reference/indexerConstraints2.errors.txt b/tests/baselines/reference/indexerConstraints2.errors.txt index 7e13c2ba399..b8b76a69f71 100644 --- a/tests/baselines/reference/indexerConstraints2.errors.txt +++ b/tests/baselines/reference/indexerConstraints2.errors.txt @@ -4,9 +4,12 @@ tests/cases/compiler/indexerConstraints2.ts(26,5): error TS2413: Numeric index t tests/cases/compiler/indexerConstraints2.ts(34,6): error TS1336: An index signature parameter type cannot be a type alias. Use '[index: number]' instead. tests/cases/compiler/indexerConstraints2.ts(40,6): error TS1336: An index signature parameter type cannot be a type alias. Use '[index: string]' instead. tests/cases/compiler/indexerConstraints2.ts(46,6): error TS1023: An index signature parameter type must be 'string' or 'number'. +tests/cases/compiler/indexerConstraints2.ts(52,6): error TS1337: An index signature parameter type cannot be a union type. Use '[K in IndexableUnion]' instead. +tests/cases/compiler/indexerConstraints2.ts(58,6): error TS1023: An index signature parameter type must be 'string' or 'number'. +tests/cases/compiler/indexerConstraints2.ts(64,6): error TS1023: An index signature parameter type must be 'string' or 'number'. -==== tests/cases/compiler/indexerConstraints2.ts (6 errors) ==== +==== tests/cases/compiler/indexerConstraints2.ts (9 errors) ==== class A { a: number; } class B extends A { b: number; } @@ -64,5 +67,29 @@ tests/cases/compiler/indexerConstraints2.ts(46,6): error TS1023: An index signat interface N { [b: AliasedBoolean]: A; ~ +!!! error TS1023: An index signature parameter type must be 'string' or 'number'. + } + + type IndexableUnion = "foo" | 42; + + interface O { + [u: IndexableUnion]: A; + ~ +!!! error TS1337: An index signature parameter type cannot be a union type. Use '[K in IndexableUnion]' instead. + } + + type NonIndexableUnion = boolean | {}; + + interface P { + [u: NonIndexableUnion]: A; + ~ +!!! error TS1023: An index signature parameter type must be 'string' or 'number'. + } + + type NonIndexableUnion2 = string | number; + + interface Q { + [u: NonIndexableUnion2]: A; + ~ !!! error TS1023: An index signature parameter type must be 'string' or 'number'. } \ No newline at end of file diff --git a/tests/baselines/reference/indexerConstraints2.js b/tests/baselines/reference/indexerConstraints2.js index 56da818e37d..ec7b2ca0646 100644 --- a/tests/baselines/reference/indexerConstraints2.js +++ b/tests/baselines/reference/indexerConstraints2.js @@ -45,6 +45,24 @@ type AliasedBoolean = boolean; interface N { [b: AliasedBoolean]: A; +} + +type IndexableUnion = "foo" | 42; + +interface O { + [u: IndexableUnion]: A; +} + +type NonIndexableUnion = boolean | {}; + +interface P { + [u: NonIndexableUnion]: A; +} + +type NonIndexableUnion2 = string | number; + +interface Q { + [u: NonIndexableUnion2]: A; } //// [indexerConstraints2.js] diff --git a/tests/baselines/reference/indexerConstraints2.symbols b/tests/baselines/reference/indexerConstraints2.symbols index 96f2b84127e..63e0423074e 100644 --- a/tests/baselines/reference/indexerConstraints2.symbols +++ b/tests/baselines/reference/indexerConstraints2.symbols @@ -99,3 +99,39 @@ interface N { >AliasedBoolean : Symbol(AliasedBoolean, Decl(indexerConstraints2.ts, 40, 1)) >A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0)) } + +type IndexableUnion = "foo" | 42; +>IndexableUnion : Symbol(IndexableUnion, Decl(indexerConstraints2.ts, 46, 1)) + +interface O { +>O : Symbol(O, Decl(indexerConstraints2.ts, 48, 33)) + + [u: IndexableUnion]: A; +>u : Symbol(u, Decl(indexerConstraints2.ts, 51, 5)) +>IndexableUnion : Symbol(IndexableUnion, Decl(indexerConstraints2.ts, 46, 1)) +>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0)) +} + +type NonIndexableUnion = boolean | {}; +>NonIndexableUnion : Symbol(NonIndexableUnion, Decl(indexerConstraints2.ts, 52, 1)) + +interface P { +>P : Symbol(P, Decl(indexerConstraints2.ts, 54, 38)) + + [u: NonIndexableUnion]: A; +>u : Symbol(u, Decl(indexerConstraints2.ts, 57, 5)) +>NonIndexableUnion : Symbol(NonIndexableUnion, Decl(indexerConstraints2.ts, 52, 1)) +>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0)) +} + +type NonIndexableUnion2 = string | number; +>NonIndexableUnion2 : Symbol(NonIndexableUnion2, Decl(indexerConstraints2.ts, 58, 1)) + +interface Q { +>Q : Symbol(Q, Decl(indexerConstraints2.ts, 60, 42)) + + [u: NonIndexableUnion2]: A; +>u : Symbol(u, Decl(indexerConstraints2.ts, 63, 5)) +>NonIndexableUnion2 : Symbol(NonIndexableUnion2, Decl(indexerConstraints2.ts, 58, 1)) +>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0)) +} diff --git a/tests/baselines/reference/indexerConstraints2.types b/tests/baselines/reference/indexerConstraints2.types index 29fb2526e84..d3abcdceaed 100644 --- a/tests/baselines/reference/indexerConstraints2.types +++ b/tests/baselines/reference/indexerConstraints2.types @@ -99,3 +99,39 @@ interface N { >AliasedBoolean : boolean >A : A } + +type IndexableUnion = "foo" | 42; +>IndexableUnion : IndexableUnion + +interface O { +>O : O + + [u: IndexableUnion]: A; +>u : IndexableUnion +>IndexableUnion : IndexableUnion +>A : A +} + +type NonIndexableUnion = boolean | {}; +>NonIndexableUnion : NonIndexableUnion + +interface P { +>P : P + + [u: NonIndexableUnion]: A; +>u : NonIndexableUnion +>NonIndexableUnion : NonIndexableUnion +>A : A +} + +type NonIndexableUnion2 = string | number; +>NonIndexableUnion2 : NonIndexableUnion2 + +interface Q { +>Q : Q + + [u: NonIndexableUnion2]: A; +>u : NonIndexableUnion2 +>NonIndexableUnion2 : NonIndexableUnion2 +>A : A +} diff --git a/tests/cases/compiler/indexerConstraints2.ts b/tests/cases/compiler/indexerConstraints2.ts index 9a2e21cc4a1..6e790c29883 100644 --- a/tests/cases/compiler/indexerConstraints2.ts +++ b/tests/cases/compiler/indexerConstraints2.ts @@ -44,4 +44,22 @@ type AliasedBoolean = boolean; interface N { [b: AliasedBoolean]: A; +} + +type IndexableUnion = "foo" | 42; + +interface O { + [u: IndexableUnion]: A; +} + +type NonIndexableUnion = boolean | {}; + +interface P { + [u: NonIndexableUnion]: A; +} + +type NonIndexableUnion2 = string | number; + +interface Q { + [u: NonIndexableUnion2]: A; } \ No newline at end of file