Skip to content

Commit ee7fdf3

Browse files
committed
fix(25770): add diagnostic message for the possible mapped type used as an index
1 parent 668bbc6 commit ee7fdf3

7 files changed

+216
-3
lines changed

src/compiler/checker.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -2246,16 +2246,28 @@ namespace ts {
22462246
}
22472247
const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false));
22482248
if (symbol && !(symbol.flags & SymbolFlags.NamespaceModule)) {
2249-
const message = isES2015OrLaterConstructorName(name)
2250-
? Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later
2251-
: Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here;
2249+
const message = isES2015OrLaterConstructorName(name) ?
2250+
Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later :
2251+
maybeMappedType(errorLocation, symbol) ?
2252+
Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_K_in_0 :
2253+
Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here;
22522254
error(errorLocation, message, unescapeLeadingUnderscores(name));
22532255
return true;
22542256
}
22552257
}
22562258
return false;
22572259
}
22582260

2261+
function maybeMappedType(node: Node, symbol: Symbol) {
2262+
const container = findAncestor(node.parent, n =>
2263+
isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined;
2264+
if (container && container.members.length === 1) {
2265+
const type = getDeclaredTypeOfSymbol(symbol);
2266+
return !!(type.flags & TypeFlags.Union) && allTypesAssignableToKind(type, TypeFlags.StringOrNumberLiteral, /*strict*/ true);
2267+
}
2268+
return false;
2269+
}
2270+
22592271
function isES2015OrLaterConstructorName(n: __String) {
22602272
switch (n) {
22612273
case "Promise":

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -2607,6 +2607,10 @@
26072607
"category": "Error",
26082608
"code": 2689
26092609
},
2610+
"'{0}' only refers to a type, but is being used as a value here. Did you mean to use 'K in {0}'?": {
2611+
"category": "Error",
2612+
"code": 2690
2613+
},
26102614
"An import path cannot end with a '{0}' extension. Consider importing '{1}' instead.": {
26112615
"category": "Error",
26122616
"code": 2691
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(8,5): error TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
2+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(8,6): error TS2690: 'K2' only refers to a type, but is being used as a value here. Did you mean to use 'K in K2'?
3+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(11,6): error TS2300: Duplicate identifier 'K3'.
4+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(12,6): error TS2300: Duplicate identifier 'T3'.
5+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(13,5): error TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
6+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(13,6): error TS2690: 'K3' only refers to a type, but is being used as a value here. Did you mean to use 'K in K3'?
7+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(16,6): error TS2300: Duplicate identifier 'K3'.
8+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(17,6): error TS2300: Duplicate identifier 'T3'.
9+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(18,5): error TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
10+
tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts(18,6): error TS2693: 'K3' only refers to a type, but is being used as a value here.
11+
12+
13+
==== tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts (10 errors) ====
14+
const K1 = Symbol();
15+
type T1 = {
16+
[K1]: number;
17+
}
18+
19+
type K2 = "x" | "y";
20+
type T2 = {
21+
[K2]: number;
22+
~~~~
23+
!!! error TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
24+
~~
25+
!!! error TS2690: 'K2' only refers to a type, but is being used as a value here. Did you mean to use 'K in K2'?
26+
}
27+
28+
type K3 = number | string;
29+
~~
30+
!!! error TS2300: Duplicate identifier 'K3'.
31+
type T3 = {
32+
~~
33+
!!! error TS2300: Duplicate identifier 'T3'.
34+
[K3]: number;
35+
~~~~
36+
!!! error TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
37+
~~
38+
!!! error TS2690: 'K3' only refers to a type, but is being used as a value here. Did you mean to use 'K in K3'?
39+
}
40+
41+
type K3 = number | string;
42+
~~
43+
!!! error TS2300: Duplicate identifier 'K3'.
44+
type T3 = {
45+
~~
46+
!!! error TS2300: Duplicate identifier 'T3'.
47+
[K3]: number;
48+
~~~~
49+
!!! error TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
50+
~~
51+
!!! error TS2693: 'K3' only refers to a type, but is being used as a value here.
52+
k4: string;
53+
}
54+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [typeUsedAsTypeLiteralIndex.ts]
2+
const K1 = Symbol();
3+
type T1 = {
4+
[K1]: number;
5+
}
6+
7+
type K2 = "x" | "y";
8+
type T2 = {
9+
[K2]: number;
10+
}
11+
12+
type K3 = number | string;
13+
type T3 = {
14+
[K3]: number;
15+
}
16+
17+
type K3 = number | string;
18+
type T3 = {
19+
[K3]: number;
20+
k4: string;
21+
}
22+
23+
24+
//// [typeUsedAsTypeLiteralIndex.js]
25+
const K1 = Symbol();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts ===
2+
const K1 = Symbol();
3+
>K1 : Symbol(K1, Decl(typeUsedAsTypeLiteralIndex.ts, 0, 5))
4+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
5+
6+
type T1 = {
7+
>T1 : Symbol(T1, Decl(typeUsedAsTypeLiteralIndex.ts, 0, 20))
8+
9+
[K1]: number;
10+
>[K1] : Symbol([K1], Decl(typeUsedAsTypeLiteralIndex.ts, 1, 11))
11+
>K1 : Symbol(K1, Decl(typeUsedAsTypeLiteralIndex.ts, 0, 5))
12+
}
13+
14+
type K2 = "x" | "y";
15+
>K2 : Symbol(K2, Decl(typeUsedAsTypeLiteralIndex.ts, 3, 1))
16+
17+
type T2 = {
18+
>T2 : Symbol(T2, Decl(typeUsedAsTypeLiteralIndex.ts, 5, 20))
19+
20+
[K2]: number;
21+
>[K2] : Symbol([K2], Decl(typeUsedAsTypeLiteralIndex.ts, 6, 11))
22+
}
23+
24+
type K3 = number | string;
25+
>K3 : Symbol(K3, Decl(typeUsedAsTypeLiteralIndex.ts, 8, 1))
26+
27+
type T3 = {
28+
>T3 : Symbol(T3, Decl(typeUsedAsTypeLiteralIndex.ts, 10, 26))
29+
30+
[K3]: number;
31+
>[K3] : Symbol([K3], Decl(typeUsedAsTypeLiteralIndex.ts, 11, 11))
32+
}
33+
34+
type K3 = number | string;
35+
>K3 : Symbol(K3, Decl(typeUsedAsTypeLiteralIndex.ts, 13, 1))
36+
37+
type T3 = {
38+
>T3 : Symbol(T3, Decl(typeUsedAsTypeLiteralIndex.ts, 15, 26))
39+
40+
[K3]: number;
41+
>[K3] : Symbol([K3], Decl(typeUsedAsTypeLiteralIndex.ts, 16, 11))
42+
43+
k4: string;
44+
>k4 : Symbol(k4, Decl(typeUsedAsTypeLiteralIndex.ts, 17, 17))
45+
}
46+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
=== tests/cases/compiler/typeUsedAsTypeLiteralIndex.ts ===
2+
const K1 = Symbol();
3+
>K1 : unique symbol
4+
>Symbol() : unique symbol
5+
>Symbol : SymbolConstructor
6+
7+
type T1 = {
8+
>T1 : T1
9+
10+
[K1]: number;
11+
>[K1] : number
12+
>K1 : unique symbol
13+
}
14+
15+
type K2 = "x" | "y";
16+
>K2 : K2
17+
18+
type T2 = {
19+
>T2 : T2
20+
21+
[K2]: number;
22+
>[K2] : number
23+
>K2 : any
24+
}
25+
26+
type K3 = number | string;
27+
>K3 : K3
28+
29+
type T3 = {
30+
>T3 : T3
31+
32+
[K3]: number;
33+
>[K3] : number
34+
>K3 : any
35+
}
36+
37+
type K3 = number | string;
38+
>K3 : K3
39+
40+
type T3 = {
41+
>T3 : { k4: string; }
42+
43+
[K3]: number;
44+
>[K3] : number
45+
>K3 : any
46+
47+
k4: string;
48+
>k4 : string
49+
}
50+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @target: esnext
2+
3+
const K1 = Symbol();
4+
type T1 = {
5+
[K1]: number;
6+
}
7+
8+
type K2 = "x" | "y";
9+
type T2 = {
10+
[K2]: number;
11+
}
12+
13+
type K3 = number | string;
14+
type T3 = {
15+
[K3]: number;
16+
}
17+
18+
type K3 = number | string;
19+
type T3 = {
20+
[K3]: number;
21+
k4: string;
22+
}

0 commit comments

Comments
 (0)