Skip to content

Commit

Permalink
Merge pull request #20726 from kujon/indexable_types
Browse files Browse the repository at this point in the history
Improved error messaging for index signature parameters
  • Loading branch information
DanielRosenwasser authored Jan 8, 2018
2 parents 0ecdc87 + c92c7a5 commit 6d596c0
Show file tree
Hide file tree
Showing 7 changed files with 375 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25864,6 +25864,21 @@ namespace ts {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation);
}
if (parameter.type.kind !== SyntaxKind.StringKeyword && parameter.type.kind !== SyntaxKind.NumberKeyword) {
const type = getTypeFromTypeNode(parameter.type);

if (type.flags & TypeFlags.String || type.flags & TypeFlags.Number) {
return grammarErrorOnNode(parameter.name,
Diagnostics.An_index_signature_parameter_type_cannot_be_a_type_alias_Consider_writing_0_Colon_1_Colon_2_instead,
getTextOfNode(parameter.name),
typeToString(type),
typeToString(getTypeFromTypeNode(node.type)));
}

if (allTypesAssignableToKind(type, TypeFlags.StringLiteral, /*strict*/ true)) {
return grammarErrorOnNode(parameter.name,
Diagnostics.An_index_signature_parameter_type_cannot_be_a_union_type_Consider_using_a_mapped_object_type_instead);
}

return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_or_number);
}
if (!node.type) {
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,14 @@
"category": "Error",
"code": 1335
},
"An index signature parameter type cannot be a type alias. Consider writing '[{0}: {1}]: {2}' instead.": {
"category": "Error",
"code": 1336
},
"An index signature parameter type cannot be a union type. Consider using a mapped object type instead.": {
"category": "Error",
"code": 1337
},

"Duplicate identifier '{0}'.": {
"category": "Error",
Expand Down
73 changes: 72 additions & 1 deletion tests/baselines/reference/indexerConstraints2.errors.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
tests/cases/compiler/indexerConstraints2.ts(9,5): error TS2413: Numeric index type 'A' is not assignable to string index type 'B'.
tests/cases/compiler/indexerConstraints2.ts(17,5): error TS2413: Numeric index type 'A' is not assignable to string index type 'B'.
tests/cases/compiler/indexerConstraints2.ts(26,5): error TS2413: Numeric index type 'A' is not assignable to string index type 'B'.
tests/cases/compiler/indexerConstraints2.ts(34,6): error TS1336: An index signature parameter type cannot be a type alias. Consider writing '[n: number]: A' instead.
tests/cases/compiler/indexerConstraints2.ts(40,6): error TS1336: An index signature parameter type cannot be a type alias. Consider writing '[s: string]: A' 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. Consider using a mapped object type 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(70,6): error TS1023: An index signature parameter type must be 'string' or 'number'.
tests/cases/compiler/indexerConstraints2.ts(74,6): error TS1337: An index signature parameter type cannot be a union type. Consider using a mapped object type instead.


==== tests/cases/compiler/indexerConstraints2.ts (3 errors) ====
==== tests/cases/compiler/indexerConstraints2.ts (11 errors) ====
class A { a: number; }
class B extends A { b: number; }

Expand Down Expand Up @@ -37,4 +45,67 @@ tests/cases/compiler/indexerConstraints2.ts(26,5): error TS2413: Numeric index t
~~~~~~~~~~~~~~~
!!! error TS2413: Numeric index type 'A' is not assignable to string index type 'B'.
[s: string]: B;
}


type AliasedNumber = number;

interface L {
[n: AliasedNumber]: A;
~
!!! error TS1336: An index signature parameter type cannot be a type alias. Consider writing '[n: number]: A' instead.
}

type AliasedString = string;

interface M {
[s: AliasedString]: A;
~
!!! error TS1336: An index signature parameter type cannot be a type alias. Consider writing '[s: string]: A' instead.
}

type AliasedBoolean = boolean;

interface N {
[b: AliasedBoolean]: A;
~
!!! error TS1023: An index signature parameter type must be 'string' or 'number'.
}

type IndexableUnion = "foo" | "bar";

interface O {
[u: IndexableUnion]: A;
~
!!! error TS1337: An index signature parameter type cannot be a union type. Consider using a mapped object type 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'.
}

type NonIndexableUnion3 = "foo" | 42;

interface R {
[u: NonIndexableUnion3]: A;
~
!!! error TS1023: An index signature parameter type must be 'string' or 'number'.
}

interface S {
[u: "foo" | "bar"]: A;
~
!!! error TS1337: An index signature parameter type cannot be a union type. Consider using a mapped object type instead.
}
47 changes: 47 additions & 0 deletions tests/baselines/reference/indexerConstraints2.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,53 @@ class J {
class K extends J {
[n: number]: A;
[s: string]: B;
}


type AliasedNumber = number;

interface L {
[n: AliasedNumber]: A;
}

type AliasedString = string;

interface M {
[s: AliasedString]: A;
}

type AliasedBoolean = boolean;

interface N {
[b: AliasedBoolean]: A;
}

type IndexableUnion = "foo" | "bar";

interface O {
[u: IndexableUnion]: A;
}

type NonIndexableUnion = boolean | {};

interface P {
[u: NonIndexableUnion]: A;
}

type NonIndexableUnion2 = string | number;

interface Q {
[u: NonIndexableUnion2]: A;
}

type NonIndexableUnion3 = "foo" | 42;

interface R {
[u: NonIndexableUnion3]: A;
}

interface S {
[u: "foo" | "bar"]: A;
}

//// [indexerConstraints2.js]
Expand Down
93 changes: 93 additions & 0 deletions tests/baselines/reference/indexerConstraints2.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,96 @@ class K extends J {
>s : Symbol(s, Decl(indexerConstraints2.ts, 26, 5))
>B : Symbol(B, Decl(indexerConstraints2.ts, 0, 22))
}


type AliasedNumber = number;
>AliasedNumber : Symbol(AliasedNumber, Decl(indexerConstraints2.ts, 27, 1))

interface L {
>L : Symbol(L, Decl(indexerConstraints2.ts, 30, 28))

[n: AliasedNumber]: A;
>n : Symbol(n, Decl(indexerConstraints2.ts, 33, 5))
>AliasedNumber : Symbol(AliasedNumber, Decl(indexerConstraints2.ts, 27, 1))
>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0))
}

type AliasedString = string;
>AliasedString : Symbol(AliasedString, Decl(indexerConstraints2.ts, 34, 1))

interface M {
>M : Symbol(M, Decl(indexerConstraints2.ts, 36, 28))

[s: AliasedString]: A;
>s : Symbol(s, Decl(indexerConstraints2.ts, 39, 5))
>AliasedString : Symbol(AliasedString, Decl(indexerConstraints2.ts, 34, 1))
>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0))
}

type AliasedBoolean = boolean;
>AliasedBoolean : Symbol(AliasedBoolean, Decl(indexerConstraints2.ts, 40, 1))

interface N {
>N : Symbol(N, Decl(indexerConstraints2.ts, 42, 30))

[b: AliasedBoolean]: A;
>b : Symbol(b, Decl(indexerConstraints2.ts, 45, 5))
>AliasedBoolean : Symbol(AliasedBoolean, Decl(indexerConstraints2.ts, 40, 1))
>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0))
}

type IndexableUnion = "foo" | "bar";
>IndexableUnion : Symbol(IndexableUnion, Decl(indexerConstraints2.ts, 46, 1))

interface O {
>O : Symbol(O, Decl(indexerConstraints2.ts, 48, 36))

[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))
}

type NonIndexableUnion3 = "foo" | 42;
>NonIndexableUnion3 : Symbol(NonIndexableUnion3, Decl(indexerConstraints2.ts, 64, 1))

interface R {
>R : Symbol(R, Decl(indexerConstraints2.ts, 66, 37))

[u: NonIndexableUnion3]: A;
>u : Symbol(u, Decl(indexerConstraints2.ts, 69, 5))
>NonIndexableUnion3 : Symbol(NonIndexableUnion3, Decl(indexerConstraints2.ts, 64, 1))
>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0))
}

interface S {
>S : Symbol(S, Decl(indexerConstraints2.ts, 70, 1))

[u: "foo" | "bar"]: A;
>u : Symbol(u, Decl(indexerConstraints2.ts, 73, 5))
>A : Symbol(A, Decl(indexerConstraints2.ts, 0, 0))
}
93 changes: 93 additions & 0 deletions tests/baselines/reference/indexerConstraints2.types
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,96 @@ class K extends J {
>s : string
>B : B
}


type AliasedNumber = number;
>AliasedNumber : number

interface L {
>L : L

[n: AliasedNumber]: A;
>n : number
>AliasedNumber : number
>A : A
}

type AliasedString = string;
>AliasedString : string

interface M {
>M : M

[s: AliasedString]: A;
>s : string
>AliasedString : string
>A : A
}

type AliasedBoolean = boolean;
>AliasedBoolean : boolean

interface N {
>N : N

[b: AliasedBoolean]: A;
>b : boolean
>AliasedBoolean : boolean
>A : A
}

type IndexableUnion = "foo" | "bar";
>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
}

type NonIndexableUnion3 = "foo" | 42;
>NonIndexableUnion3 : NonIndexableUnion3

interface R {
>R : R

[u: NonIndexableUnion3]: A;
>u : NonIndexableUnion3
>NonIndexableUnion3 : NonIndexableUnion3
>A : A
}

interface S {
>S : S

[u: "foo" | "bar"]: A;
>u : IndexableUnion
>A : A
}
Loading

0 comments on commit 6d596c0

Please sign in to comment.