Skip to content

Commit 5dce990

Browse files
committed
Increase strictness on index signatures with type unknown so inference doesnt change surprisingly
1 parent f907b50 commit 5dce990

15 files changed

+152
-31
lines changed

src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13350,7 +13350,7 @@ namespace ts {
1335013350
return indexTypesIdenticalTo(source, target, kind);
1335113351
}
1335213352
const targetInfo = getIndexInfoOfType(target, kind);
13353-
if (!targetInfo || targetInfo.type.flags & TypeFlags.AnyOrUnknown && !sourceIsPrimitive) {
13353+
if (!targetInfo || targetInfo.type.flags & TypeFlags.Any && !sourceIsPrimitive) {
1335413354
// Index signature of type any permits assignment from everything but primitives
1335513355
return Ternary.True;
1335613356
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts(9,3): error TS2345: Argument of type '{ name: string; age: number; }[]' is not assignable to parameter of type '{ [x: string]: unknown; }'.
2+
Index signature is missing in type '{ name: string; age: number; }[]'.
3+
4+
5+
==== tests/cases/compiler/indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts (1 errors) ====
6+
declare function f<T extends unknown = unknown>(x: { [x: string]: T }): T;
7+
8+
var stooges = [
9+
{ name: "moe", age: 40 },
10+
{ name: "larry", age: 50 },
11+
{ name: "curly", age: 60 }
12+
];
13+
14+
f(stooges); // Should throw
15+
~~~~~~~
16+
!!! error TS2345: Argument of type '{ name: string; age: number; }[]' is not assignable to parameter of type '{ [x: string]: unknown; }'.
17+
!!! error TS2345: Index signature is missing in type '{ name: string; age: number; }[]'.
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts]
2+
declare function f<T extends unknown = unknown>(x: { [x: string]: T }): T;
3+
4+
var stooges = [
5+
{ name: "moe", age: 40 },
6+
{ name: "larry", age: 50 },
7+
{ name: "curly", age: 60 }
8+
];
9+
10+
f(stooges); // Should throw
11+
12+
13+
//// [indexSignatureOfTypeUnknownStillRequiresIndexSignature.js]
14+
var stooges = [
15+
{ name: "moe", age: 40 },
16+
{ name: "larry", age: 50 },
17+
{ name: "curly", age: 60 }
18+
];
19+
f(stooges); // Should throw
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=== tests/cases/compiler/indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts ===
2+
declare function f<T extends unknown = unknown>(x: { [x: string]: T }): T;
3+
>f : Symbol(f, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 0, 0))
4+
>T : Symbol(T, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 0, 19))
5+
>x : Symbol(x, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 0, 48))
6+
>x : Symbol(x, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 0, 54))
7+
>T : Symbol(T, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 0, 19))
8+
>T : Symbol(T, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 0, 19))
9+
10+
var stooges = [
11+
>stooges : Symbol(stooges, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 2, 3))
12+
13+
{ name: "moe", age: 40 },
14+
>name : Symbol(name, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 3, 3))
15+
>age : Symbol(age, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 3, 16))
16+
17+
{ name: "larry", age: 50 },
18+
>name : Symbol(name, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 4, 3))
19+
>age : Symbol(age, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 4, 18))
20+
21+
{ name: "curly", age: 60 }
22+
>name : Symbol(name, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 5, 3))
23+
>age : Symbol(age, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 5, 18))
24+
25+
];
26+
27+
f(stooges); // Should throw
28+
>f : Symbol(f, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 0, 0))
29+
>stooges : Symbol(stooges, Decl(indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts, 2, 3))
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
=== tests/cases/compiler/indexSignatureOfTypeUnknownStillRequiresIndexSignature.ts ===
2+
declare function f<T extends unknown = unknown>(x: { [x: string]: T }): T;
3+
>f : <T extends unknown = unknown>(x: { [x: string]: T; }) => T
4+
>x : { [x: string]: T; }
5+
>x : string
6+
7+
var stooges = [
8+
>stooges : { name: string; age: number; }[]
9+
>[ { name: "moe", age: 40 }, { name: "larry", age: 50 }, { name: "curly", age: 60 }] : { name: string; age: number; }[]
10+
11+
{ name: "moe", age: 40 },
12+
>{ name: "moe", age: 40 } : { name: string; age: number; }
13+
>name : string
14+
>"moe" : "moe"
15+
>age : number
16+
>40 : 40
17+
18+
{ name: "larry", age: 50 },
19+
>{ name: "larry", age: 50 } : { name: string; age: number; }
20+
>name : string
21+
>"larry" : "larry"
22+
>age : number
23+
>50 : 50
24+
25+
{ name: "curly", age: 60 }
26+
>{ name: "curly", age: 60 } : { name: string; age: number; }
27+
>name : string
28+
>"curly" : "curly"
29+
>age : number
30+
>60 : 60
31+
32+
];
33+
34+
f(stooges); // Should throw
35+
>f(stooges) : any
36+
>f : <T extends unknown = unknown>(x: { [x: string]: T; }) => T
37+
>stooges : { name: string; age: number; }[]
38+

tests/baselines/reference/indexSignatureTypeInference.errors.txt

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
tests/cases/conformance/types/typeRelationships/typeInference/indexSignatureTypeInference.ts(18,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'v1' must be of type 'Function[]', but here has type 'unknown[]'.
1+
tests/cases/conformance/types/typeRelationships/typeInference/indexSignatureTypeInference.ts(18,27): error TS2345: Argument of type 'NumberMap<Function>' is not assignable to parameter of type 'StringMap<unknown>'.
2+
Index signature is missing in type 'NumberMap<Function>'.
23

34

45
==== tests/cases/conformance/types/typeRelationships/typeInference/indexSignatureTypeInference.ts (1 errors) ====
@@ -20,7 +21,8 @@ tests/cases/conformance/types/typeRelationships/typeInference/indexSignatureType
2021
var v1 = numberMapToArray(numberMap); // Ok
2122
var v1 = numberMapToArray(stringMap); // Ok
2223
var v1 = stringMapToArray(numberMap); // Error expected here
23-
~~
24-
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'v1' must be of type 'Function[]', but here has type 'unknown[]'.
24+
~~~~~~~~~
25+
!!! error TS2345: Argument of type 'NumberMap<Function>' is not assignable to parameter of type 'StringMap<unknown>'.
26+
!!! error TS2345: Index signature is missing in type 'NumberMap<Function>'.
2527
var v1 = stringMapToArray(stringMap); // Ok
2628

tests/baselines/reference/indexSignatureTypeInference.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ var v1 = numberMapToArray(stringMap); // Ok
4040

4141
var v1 = stringMapToArray(numberMap); // Error expected here
4242
>v1 : Function[]
43-
>stringMapToArray(numberMap) : unknown[]
43+
>stringMapToArray(numberMap) : any
4444
>stringMapToArray : <T>(object: StringMap<T>) => T[]
4545
>numberMap : NumberMap<Function>
4646

tests/baselines/reference/underscoreTest1.errors.txt

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
tests/cases/compiler/underscoreTest1_underscoreTests.ts(26,31): error TS2345: Argument of type '<T>(value: T) => T' is not assignable to parameter of type 'Iterator_<unknown, boolean>'.
2-
Type 'unknown' is not assignable to type 'boolean'.
1+
tests/cases/compiler/underscoreTest1_underscoreTests.ts(26,7): error TS2345: Argument of type '(string | number | boolean)[]' is not assignable to parameter of type 'Dictionary<unknown>'.
2+
Index signature is missing in type '(string | number | boolean)[]'.
33

44

55
==== tests/cases/compiler/underscoreTest1_underscoreTests.ts (1 errors) ====
@@ -29,9 +29,9 @@ tests/cases/compiler/underscoreTest1_underscoreTests.ts(26,31): error TS2345: Ar
2929
var odds = _.reject([1, 2, 3, 4, 5, 6], (num) => num % 2 == 0);
3030

3131
_.all([true, 1, null, 'yes'], _.identity);
32-
~~~~~~~~~~
33-
!!! error TS2345: Argument of type '<T>(value: T) => T' is not assignable to parameter of type 'Iterator_<unknown, boolean>'.
34-
!!! error TS2345: Type 'unknown' is not assignable to type 'boolean'.
32+
~~~~~~~~~~~~~~~~~~~~~~
33+
!!! error TS2345: Argument of type '(string | number | boolean)[]' is not assignable to parameter of type 'Dictionary<unknown>'.
34+
!!! error TS2345: Index signature is missing in type '(string | number | boolean)[]'.
3535

3636
_.any([null, 0, 'yes', false]);
3737

tests/baselines/reference/unknownType1.errors.txt

+8-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ tests/cases/conformance/types/unknown/unknownType1.ts(114,9): error TS2322: Type
1818
Type 'unknown' is not assignable to type '{}'.
1919
tests/cases/conformance/types/unknown/unknownType1.ts(120,9): error TS2322: Type 'T' is not assignable to type 'object'.
2020
Type 'unknown' is not assignable to type 'object'.
21+
tests/cases/conformance/types/unknown/unknownType1.ts(128,5): error TS2322: Type 'number[]' is not assignable to type '{ [x: string]: unknown; }'.
22+
Index signature is missing in type 'number[]'.
2123
tests/cases/conformance/types/unknown/unknownType1.ts(129,5): error TS2322: Type '123' is not assignable to type '{ [x: string]: unknown; }'.
2224
tests/cases/conformance/types/unknown/unknownType1.ts(149,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
2325
tests/cases/conformance/types/unknown/unknownType1.ts(155,14): error TS2700: Rest types may only be created from object types.
@@ -28,7 +30,7 @@ tests/cases/conformance/types/unknown/unknownType1.ts(180,5): error TS2322: Type
2830
Type 'unknown' is not assignable to type '{}'.
2931

3032

31-
==== tests/cases/conformance/types/unknown/unknownType1.ts (24 errors) ====
33+
==== tests/cases/conformance/types/unknown/unknownType1.ts (25 errors) ====
3234
// In an intersection everything absorbs unknown
3335

3436
type T00 = unknown & null; // null
@@ -189,12 +191,15 @@ tests/cases/conformance/types/unknown/unknownType1.ts(180,5): error TS2322: Type
189191
!!! error TS2322: Type 'unknown' is not assignable to type 'object'.
190192
}
191193

192-
// Anything but primitive assignable to { [x: string]: unknown }
194+
// Anything fresh but primitive assignable to { [x: string]: unknown }
193195

194196
function f24(x: { [x: string]: unknown }) {
195197
x = {};
196198
x = { a: 5 };
197-
x = [1, 2, 3];
199+
x = [1, 2, 3]; // Error
200+
~
201+
!!! error TS2322: Type 'number[]' is not assignable to type '{ [x: string]: unknown; }'.
202+
!!! error TS2322: Index signature is missing in type 'number[]'.
198203
x = 123; // Error
199204
~
200205
!!! error TS2322: Type '123' is not assignable to type '{ [x: string]: unknown; }'.

tests/baselines/reference/unknownType1.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ function f23<T extends unknown>(x: T) {
121121
let y: object = x; // Error
122122
}
123123

124-
// Anything but primitive assignable to { [x: string]: unknown }
124+
// Anything fresh but primitive assignable to { [x: string]: unknown }
125125

126126
function f24(x: { [x: string]: unknown }) {
127127
x = {};
128128
x = { a: 5 };
129-
x = [1, 2, 3];
129+
x = [1, 2, 3]; // Error
130130
x = 123; // Error
131131
}
132132

@@ -262,11 +262,11 @@ function f22(x) {
262262
function f23(x) {
263263
var y = x; // Error
264264
}
265-
// Anything but primitive assignable to { [x: string]: unknown }
265+
// Anything fresh but primitive assignable to { [x: string]: unknown }
266266
function f24(x) {
267267
x = {};
268268
x = { a: 5 };
269-
x = [1, 2, 3];
269+
x = [1, 2, 3]; // Error
270270
x = 123; // Error
271271
}
272272
// Locals of type unknown always considered initialized

tests/baselines/reference/unknownType1.symbols

+2-2
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ function f23<T extends unknown>(x: T) {
314314
>x : Symbol(x, Decl(unknownType1.ts, 118, 32))
315315
}
316316

317-
// Anything but primitive assignable to { [x: string]: unknown }
317+
// Anything fresh but primitive assignable to { [x: string]: unknown }
318318

319319
function f24(x: { [x: string]: unknown }) {
320320
>f24 : Symbol(f24, Decl(unknownType1.ts, 120, 1))
@@ -328,7 +328,7 @@ function f24(x: { [x: string]: unknown }) {
328328
>x : Symbol(x, Decl(unknownType1.ts, 124, 13))
329329
>a : Symbol(a, Decl(unknownType1.ts, 126, 9))
330330

331-
x = [1, 2, 3];
331+
x = [1, 2, 3]; // Error
332332
>x : Symbol(x, Decl(unknownType1.ts, 124, 13))
333333

334334
x = 123; // Error

tests/baselines/reference/unknownType1.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ function f23<T extends unknown>(x: T) {
342342
>x : T
343343
}
344344

345-
// Anything but primitive assignable to { [x: string]: unknown }
345+
// Anything fresh but primitive assignable to { [x: string]: unknown }
346346

347347
function f24(x: { [x: string]: unknown }) {
348348
>f24 : (x: { [x: string]: unknown; }) => void
@@ -361,7 +361,7 @@ function f24(x: { [x: string]: unknown }) {
361361
>a : number
362362
>5 : 5
363363

364-
x = [1, 2, 3];
364+
x = [1, 2, 3]; // Error
365365
>x = [1, 2, 3] : number[]
366366
>x : { [x: string]: unknown; }
367367
>[1, 2, 3] : number[]

tests/baselines/reference/useObjectValuesAndEntries1.types

+8-8
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,16 @@ enum E { A, B }
121121
>B : E.B
122122

123123
var entries5 = Object.entries(E); // [string, any][]
124-
>entries5 : [string, unknown][]
125-
>Object.entries(E) : [string, unknown][]
124+
>entries5 : [string, any][]
125+
>Object.entries(E) : [string, any][]
126126
>Object.entries : { <T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][]; (o: {}): [string, any][]; }
127127
>Object : ObjectConstructor
128128
>entries : { <T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][]; (o: {}): [string, any][]; }
129129
>E : typeof E
130130

131131
var values5 = Object.values(E); // any[]
132-
>values5 : unknown[]
133-
>Object.values(E) : unknown[]
132+
>values5 : any[]
133+
>Object.values(E) : any[]
134134
>Object.values : { <T>(o: { [s: string]: T; } | ArrayLike<T>): T[]; (o: {}): any[]; }
135135
>Object : ObjectConstructor
136136
>values : { <T>(o: { [s: string]: T; } | ArrayLike<T>): T[]; (o: {}): any[]; }
@@ -142,16 +142,16 @@ var i: I = {};
142142
>{} : {}
143143

144144
var entries6 = Object.entries(i); // [string, any][]
145-
>entries6 : [string, unknown][]
146-
>Object.entries(i) : [string, unknown][]
145+
>entries6 : [string, any][]
146+
>Object.entries(i) : [string, any][]
147147
>Object.entries : { <T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][]; (o: {}): [string, any][]; }
148148
>Object : ObjectConstructor
149149
>entries : { <T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][]; (o: {}): [string, any][]; }
150150
>i : I
151151

152152
var values6 = Object.values(i); // any[]
153-
>values6 : unknown[]
154-
>Object.values(i) : unknown[]
153+
>values6 : any[]
154+
>Object.values(i) : any[]
155155
>Object.values : { <T>(o: { [s: string]: T; } | ArrayLike<T>): T[]; (o: {}): any[]; }
156156
>Object : ObjectConstructor
157157
>values : { <T>(o: { [s: string]: T; } | ArrayLike<T>): T[]; (o: {}): any[]; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
declare function f<T extends unknown = unknown>(x: { [x: string]: T }): T;
2+
3+
var stooges = [
4+
{ name: "moe", age: 40 },
5+
{ name: "larry", age: 50 },
6+
{ name: "curly", age: 60 }
7+
];
8+
9+
f(stooges); // Should throw

tests/cases/conformance/types/unknown/unknownType1.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,12 @@ function f23<T extends unknown>(x: T) {
122122
let y: object = x; // Error
123123
}
124124

125-
// Anything but primitive assignable to { [x: string]: unknown }
125+
// Anything fresh but primitive assignable to { [x: string]: unknown }
126126

127127
function f24(x: { [x: string]: unknown }) {
128128
x = {};
129129
x = { a: 5 };
130-
x = [1, 2, 3];
130+
x = [1, 2, 3]; // Error
131131
x = 123; // Error
132132
}
133133

0 commit comments

Comments
 (0)