Skip to content

Commit 7fa7c12

Browse files
committed
Elaborate array and tuple relation errors
1 parent 4fee628 commit 7fa7c12

12 files changed

+326
-23
lines changed

src/compiler/checker.ts

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12246,6 +12246,40 @@ namespace ts {
1224612246
}
1224712247
}
1224812248

12249+
/**
12250+
* Try and elaborate array and tuple errors. Returns false
12251+
* if we have found an elaboration, or we should ignore
12252+
* any other elaborations when relating the `source` and
12253+
* `target` types.
12254+
*
12255+
* @param source
12256+
* @param target
12257+
* @param reportErrors
12258+
*/
12259+
function tryElaborateArrayLikeErrors(source: Type, target: Type, reportErrors: boolean): boolean {
12260+
if (isTupleLikeType(source)) {
12261+
const sourceTuple: TupleType | undefined = (source as TupleTypeReference).target;
12262+
if (sourceTuple && sourceTuple.readonly && isArrayOrTupleLikeType(target) &&
12263+
(!isReadonlyArrayType(target) || isTupleType(target) && !target.target.readonly)) {
12264+
if (reportErrors) {
12265+
reportError(Diagnostics.A_readonly_tuple_cannot_be_assigned_to_a_mutable_array_like_type);
12266+
}
12267+
return false;
12268+
}
12269+
return isArrayLikeType(target);
12270+
}
12271+
if (isTupleLikeType(target)) {
12272+
return isArrayLikeType(source);
12273+
}
12274+
if (isReadonlyArrayType(source) && isArrayType(target) && !isReadonlyArrayType(target)) {
12275+
if (reportErrors) {
12276+
reportError(Diagnostics.A_ReadonlyArray_cannot_be_assigned_to_an_Array_because_Array_s_can_be_mutated);
12277+
}
12278+
return false;
12279+
}
12280+
return true;
12281+
}
12282+
1224912283
function isUnionOrIntersectionTypeWithoutNullableConstituents(type: Type): boolean {
1225012284
if (!(type.flags & TypeFlags.UnionOrIntersection)) {
1225112285
return false;
@@ -12418,6 +12452,9 @@ namespace ts {
1241812452
if (!result && reportErrors) {
1241912453
const maybeSuppress = suppressNextError;
1242012454
suppressNextError = false;
12455+
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
12456+
tryElaborateArrayLikeErrors(source, target, reportErrors);
12457+
}
1242112458
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) {
1242212459
tryElaborateErrorsForPrimitivesAndObjects(source, target);
1242312460
}
@@ -13148,11 +13185,13 @@ namespace ts {
1314813185
associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
1314913186
}
1315013187
}
13151-
else if (props.length > 5) { // arbitrary cutoff for too-long list form
13152-
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
13153-
}
13154-
else {
13155-
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
13188+
else if (tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ false)) {
13189+
if (props.length > 5) { // arbitrary cutoff for too-long list form
13190+
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
13191+
}
13192+
else {
13193+
reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
13194+
}
1315613195
}
1315713196
}
1315813197
return Ternary.False;

src/compiler/diagnosticMessages.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2943,7 +2943,15 @@
29432943
"category": "Error",
29442944
"code": 4103
29452945
},
2946-
2946+
"A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.": {
2947+
"category": "Error",
2948+
"code": 4104
2949+
},
2950+
"A 'readonly' tuple cannot be assigned to a mutable array-like type.": {
2951+
"category": "Error",
2952+
"code": 4105
2953+
},
2954+
29472955
"The current host does not support the '{0}' option.": {
29482956
"category": "Error",
29492957
"code": 5001

tests/baselines/reference/iterableArrayPattern10.errors.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts(17,5): error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.
2-
Type 'FooIterator' is missing the following properties from type '[any, any]': 0, 1, length, pop, and 26 more.
32

43

54
==== tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts (1 errors) ====
@@ -21,5 +20,4 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern10.ts(17,5): error
2120
function fun([a, b]) { }
2221
fun(new FooIterator);
2322
~~~~~~~~~~~~~~~
24-
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.
25-
!!! error TS2345: Type 'FooIterator' is missing the following properties from type '[any, any]': 0, 1, length, pop, and 26 more.
23+
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, any]'.

tests/baselines/reference/iterableArrayPattern13.errors.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
tests/cases/conformance/es6/destructuring/iterableArrayPattern13.ts(17,5): error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, ...any[]]'.
2-
Type 'FooIterator' is missing the following properties from type '[any, ...any[]]': 0, length, pop, push, and 25 more.
32

43

54
==== tests/cases/conformance/es6/destructuring/iterableArrayPattern13.ts (1 errors) ====
@@ -21,5 +20,4 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern13.ts(17,5): error
2120
function fun([a, ...b]) { }
2221
fun(new FooIterator);
2322
~~~~~~~~~~~~~~~
24-
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, ...any[]]'.
25-
!!! error TS2345: Type 'FooIterator' is missing the following properties from type '[any, ...any[]]': 0, length, pop, push, and 25 more.
23+
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[any, ...any[]]'.

tests/baselines/reference/iterableArrayPattern16.errors.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts(2,5): error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[Bar, Bar]'.
2-
Type 'FooIterator' is missing the following properties from type '[Bar, Bar]': 0, 1, length, pop, and 26 more.
32
tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts(2,12): error TS2449: Class 'FooIteratorIterator' used before its declaration.
43

54

@@ -8,7 +7,6 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts(2,12): error
87
fun(...new FooIteratorIterator);
98
~~~~~~~~~~~~~~~~~~~~~~~~~~
109
!!! error TS2345: Argument of type 'FooIterator' is not assignable to parameter of type '[Bar, Bar]'.
11-
!!! error TS2345: Type 'FooIterator' is missing the following properties from type '[Bar, Bar]': 0, 1, length, pop, and 26 more.
1210
~~~~~~~~~~~~~~~~~~~
1311
!!! error TS2449: Class 'FooIteratorIterator' used before its declaration.
1412
!!! related TS2728 tests/cases/conformance/es6/destructuring/iterableArrayPattern16.ts:18:7: 'FooIteratorIterator' is declared here.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
tests/cases/conformance/es6/destructuring/iterableArrayPattern26.ts(2,21): error TS2345: Argument of type 'Map<string, number>' is not assignable to parameter of type '[string, number]'.
2-
Type 'Map<string, number>' is missing the following properties from type '[string, number]': 0, 1, length, pop, and 22 more.
32

43

54
==== tests/cases/conformance/es6/destructuring/iterableArrayPattern26.ts (1 errors) ====
65
function takeFirstTwoEntries(...[[k1, v1], [k2, v2]]: [string, number][]) { }
76
takeFirstTwoEntries(new Map([["", 0], ["hello", 1]]));
87
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9-
!!! error TS2345: Argument of type 'Map<string, number>' is not assignable to parameter of type '[string, number]'.
10-
!!! error TS2345: Type 'Map<string, number>' is missing the following properties from type '[string, number]': 0, 1, length, pop, and 22 more.
8+
!!! error TS2345: Argument of type 'Map<string, number>' is not assignable to parameter of type '[string, number]'.

tests/baselines/reference/readonlyArraysAndTuples.errors.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(9,12): error TS13
22
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(10,15): error TS1354: 'readonly' type modifier is only permitted on array and tuple literal types.
33
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(11,12): error TS1354: 'readonly' type modifier is only permitted on array and tuple literal types.
44
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(12,12): error TS1354: 'readonly' type modifier is only permitted on array and tuple literal types.
5-
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(15,5): error TS2740: Type 'readonly string[]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
6-
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(17,5): error TS2740: Type 'readonly [string, string]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
5+
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(15,5): error TS4105: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
6+
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(17,5): error TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
77
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(21,5): error TS2739: Type 'string[]' is missing the following properties from type '[string, string]': 0, 1
88
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(22,5): error TS2740: Type 'readonly string[]' is missing the following properties from type '[string, string]': 0, 1, pop, push, and 5 more.
9-
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(23,5): error TS2740: Type 'readonly [string, string]' is missing the following properties from type '[string, string]': pop, push, reverse, shift, and 3 more.
9+
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(23,5): error TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
1010
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(24,5): error TS2739: Type 'string[]' is missing the following properties from type 'readonly [string, string]': 0, 1
1111
tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(25,5): error TS2739: Type 'readonly string[]' is missing the following properties from type 'readonly [string, string]': 0, 1
1212

@@ -36,11 +36,11 @@ tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(25,5): error TS27
3636
function f1(ma: string[], ra: readonly string[], mt: [string, string], rt: readonly [string, string]) {
3737
ma = ra; // Error
3838
~~
39-
!!! error TS2740: Type 'readonly string[]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
39+
!!! error TS4105: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
4040
ma = mt;
4141
ma = rt; // Error
4242
~~
43-
!!! error TS2740: Type 'readonly [string, string]' is missing the following properties from type 'string[]': pop, push, reverse, shift, and 3 more.
43+
!!! error TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
4444
ra = ma;
4545
ra = mt;
4646
ra = rt;
@@ -52,7 +52,7 @@ tests/cases/conformance/types/tuple/readonlyArraysAndTuples.ts(25,5): error TS27
5252
!!! error TS2740: Type 'readonly string[]' is missing the following properties from type '[string, string]': 0, 1, pop, push, and 5 more.
5353
mt = rt; // Error
5454
~~
55-
!!! error TS2740: Type 'readonly [string, string]' is missing the following properties from type '[string, string]': pop, push, reverse, shift, and 3 more.
55+
!!! error TS4106: A 'readonly' tuple cannot be assigned to a mutable array-like type.
5656
rt = ma; // Error
5757
~~
5858
!!! error TS2739: Type 'string[]' is missing the following properties from type 'readonly [string, string]': 0, 1
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(10,20): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type '[number, number]'.
2+
A 'readonly' tuple cannot be assigned to a mutable array-like type.
3+
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(13,8): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
4+
A 'readonly' tuple cannot be assigned to a mutable array-like type.
5+
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(16,9): error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
6+
A 'readonly' tuple cannot be assigned to a mutable array-like type.
7+
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(22,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
8+
A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
9+
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(23,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
10+
A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
11+
tests/cases/compiler/readonlyTupleAndArrayElaboration.ts(24,9): error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
12+
A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
13+
14+
15+
==== tests/cases/compiler/readonlyTupleAndArrayElaboration.ts (6 errors) ====
16+
// @strict
17+
// #Repro from #30839
18+
19+
let point = [3, 4] as const;
20+
21+
function distanceFromOrigin([x, y]: [number, number]) {
22+
return Math.sqrt(x ** 2 + y ** 2);
23+
}
24+
25+
distanceFromOrigin(point);
26+
~~~~~
27+
!!! error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type '[number, number]'.
28+
!!! error TS2345: A 'readonly' tuple cannot be assigned to a mutable array-like type.
29+
30+
declare function arryFn(x: number[]): void;
31+
arryFn(point);
32+
~~~~~
33+
!!! error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
34+
!!! error TS2345: A 'readonly' tuple cannot be assigned to a mutable array-like type.
35+
36+
declare function arryFn2(x: Array<number>): void;
37+
arryFn2(point);
38+
~~~~~
39+
!!! error TS2345: Argument of type 'readonly [3, 4]' is not assignable to parameter of type 'number[]'.
40+
!!! error TS2345: A 'readonly' tuple cannot be assigned to a mutable array-like type.
41+
42+
declare const a: readonly number[];
43+
declare const b: Readonly<number[]>;
44+
declare const c: ReadonlyArray<number>;
45+
46+
arryFn2(a);
47+
~
48+
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
49+
!!! error TS2345: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
50+
arryFn2(b);
51+
~
52+
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
53+
!!! error TS2345: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
54+
arryFn2(c);
55+
~
56+
!!! error TS2345: Argument of type 'readonly number[]' is not assignable to parameter of type 'number[]'.
57+
!!! error TS2345: A 'ReadonlyArray' cannot be assigned to an 'Array' because 'Array's can be mutated.
58+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//// [readonlyTupleAndArrayElaboration.ts]
2+
// @strict
3+
// #Repro from #30839
4+
5+
let point = [3, 4] as const;
6+
7+
function distanceFromOrigin([x, y]: [number, number]) {
8+
return Math.sqrt(x ** 2 + y ** 2);
9+
}
10+
11+
distanceFromOrigin(point);
12+
13+
declare function arryFn(x: number[]): void;
14+
arryFn(point);
15+
16+
declare function arryFn2(x: Array<number>): void;
17+
arryFn2(point);
18+
19+
declare const a: readonly number[];
20+
declare const b: Readonly<number[]>;
21+
declare const c: ReadonlyArray<number>;
22+
23+
arryFn2(a);
24+
arryFn2(b);
25+
arryFn2(c);
26+
27+
28+
//// [readonlyTupleAndArrayElaboration.js]
29+
// @strict
30+
// #Repro from #30839
31+
var point = [3, 4];
32+
function distanceFromOrigin(_a) {
33+
var x = _a[0], y = _a[1];
34+
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
35+
}
36+
distanceFromOrigin(point);
37+
arryFn(point);
38+
arryFn2(point);
39+
arryFn2(a);
40+
arryFn2(b);
41+
arryFn2(c);

0 commit comments

Comments
 (0)