Skip to content

Commit 6465e9d

Browse files
Merge pull request #26292 from Kingwl/tupleIndexAccessCheck
check index access for fixed length tuple
2 parents c188864 + 6432bd9 commit 6465e9d

15 files changed

+315
-3
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18498,6 +18498,13 @@ namespace ts {
1849818498
error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal);
1849918499
return errorType;
1850018500
}
18501+
if (isTupleType(objectType) && !objectType.target.hasRestElement && isNumericLiteral(indexExpression)) {
18502+
const index = +indexExpression.text;
18503+
const maximumIndex = length(objectType.target.typeParameters);
18504+
if (index >= maximumIndex) {
18505+
error(indexExpression, Diagnostics.Index_0_is_out_of_bounds_in_tuple_of_length_1, index, maximumIndex);
18506+
}
18507+
}
1850118508

1850218509
return checkIndexedAccessIndexType(getIndexedAccessType(objectType, isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType, node), node);
1850318510
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2437,6 +2437,10 @@
24372437
"category": "Error",
24382438
"code": 2732
24392439
},
2440+
"Index '{0}' is out-of-bounds in tuple of length {1}.": {
2441+
"category": "Error",
2442+
"code": 2733
2443+
},
24402444

24412445
"Import declaration '{0}' is using private name '{1}'.": {
24422446
"category": "Error",
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple.ts(22,13): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
2+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple.ts(23,13): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
3+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple.ts(24,13): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
4+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple.ts(25,13): error TS2733: Index '3' is out-of-bounds in tuple of length 3.
5+
6+
7+
==== tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple.ts (4 errors) ====
8+
function f1(x: number): string { return "foo"; }
9+
10+
function f2(x: number): number { return 10; }
11+
12+
function f3(x: number): boolean { return true; }
13+
14+
enum E1 { one }
15+
16+
enum E2 { two }
17+
18+
19+
var t1: [(x: number) => string, (x: number) => number];
20+
var t2: [E1, E2];
21+
var t3: [number, any];
22+
var t4: [E1, E2, number];
23+
24+
// no error
25+
t1 = [f1, f2];
26+
t2 = [E1.one, E2.two];
27+
t3 = [5, undefined];
28+
t4 = [E1.one, E2.two, 20];
29+
var e1 = t1[2]; // {}
30+
~
31+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
32+
var e2 = t2[2]; // {}
33+
~
34+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
35+
var e3 = t3[2]; // any
36+
~
37+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
38+
var e4 = t4[3]; // number
39+
~
40+
!!! error TS2733: Index '3' is out-of-bounds in tuple of length 3.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple2.ts(17,14): error TS2733: Index '4' is out-of-bounds in tuple of length 2.
2+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple2.ts(18,14): error TS2733: Index '4' is out-of-bounds in tuple of length 2.
3+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple2.ts(19,14): error TS2733: Index '4' is out-of-bounds in tuple of length 2.
4+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple2.ts(20,14): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
5+
tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple2.ts(21,14): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
6+
7+
8+
==== tests/cases/conformance/types/typeRelationships/bestCommonType/bestCommonTypeOfTuple2.ts (5 errors) ====
9+
interface base { }
10+
interface base1 { i }
11+
class C implements base { c }
12+
class D implements base { d }
13+
class E implements base { e }
14+
class F extends C { f }
15+
16+
class C1 implements base1 { i = "foo"; c }
17+
class D1 extends C1 { i = "bar"; d }
18+
19+
var t1: [C, base];
20+
var t2: [C, D];
21+
var t3: [C1, D1];
22+
var t4: [base1, C1];
23+
var t5: [C1, F]
24+
25+
var e11 = t1[4]; // base
26+
~
27+
!!! error TS2733: Index '4' is out-of-bounds in tuple of length 2.
28+
var e21 = t2[4]; // {}
29+
~
30+
!!! error TS2733: Index '4' is out-of-bounds in tuple of length 2.
31+
var e31 = t3[4]; // C1
32+
~
33+
!!! error TS2733: Index '4' is out-of-bounds in tuple of length 2.
34+
var e41 = t4[2]; // base1
35+
~
36+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
37+
var e51 = t5[2]; // {}
38+
~
39+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
40+

tests/baselines/reference/castingTuple.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ tests/cases/conformance/types/tuple/castingTuple.ts(14,15): error TS2352: Conver
66
tests/cases/conformance/types/tuple/castingTuple.ts(15,14): error TS2352: Conversion of type '[number, string]' to type '[number, string, boolean]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
77
tests/cases/conformance/types/tuple/castingTuple.ts(18,21): error TS2352: Conversion of type '[C, D]' to type '[C, D, A]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
88
Property '2' is missing in type '[C, D]'.
9+
tests/cases/conformance/types/tuple/castingTuple.ts(20,33): error TS2733: Index '5' is out-of-bounds in tuple of length 3.
910
tests/cases/conformance/types/tuple/castingTuple.ts(30,10): error TS2352: Conversion of type '[number, string]' to type '[number, number]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
1011
Type 'string' is not comparable to type 'number'.
1112
tests/cases/conformance/types/tuple/castingTuple.ts(31,10): error TS2352: Conversion of type '[C, D]' to type '[A, I]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
@@ -15,7 +16,7 @@ tests/cases/conformance/types/tuple/castingTuple.ts(32,5): error TS2403: Subsequ
1516
tests/cases/conformance/types/tuple/castingTuple.ts(33,1): error TS2304: Cannot find name 't4'.
1617

1718

18-
==== tests/cases/conformance/types/tuple/castingTuple.ts (8 errors) ====
19+
==== tests/cases/conformance/types/tuple/castingTuple.ts (9 errors) ====
1920
interface I { }
2021
class A { a = 10; }
2122
class C implements I { c };
@@ -48,6 +49,8 @@ tests/cases/conformance/types/tuple/castingTuple.ts(33,1): error TS2304: Cannot
4849
!!! error TS2352: Property '2' is missing in type '[C, D]'.
4950
var eleFromCDA1 = classCDATuple[2]; // A
5051
var eleFromCDA2 = classCDATuple[5]; // C | D | A
52+
~
53+
!!! error TS2733: Index '5' is out-of-bounds in tuple of length 3.
5154
var t10: [E1, E2] = [E1.one, E2.one];
5255
var t11 = <[number, number]>t10;
5356
var array1 = <{}[]>emptyObjTuple;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion01.ts(2,11): error TS2733: Index '0' is out-of-bounds in tuple of length 0.
2+
3+
4+
==== tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion01.ts (1 errors) ====
5+
let x = <[]>[];
6+
let y = x[0];
7+
~
8+
!!! error TS2733: Index '0' is out-of-bounds in tuple of length 0.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion02.ts(2,11): error TS2733: Index '0' is out-of-bounds in tuple of length 0.
2+
3+
4+
==== tests/cases/conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion02.ts (1 errors) ====
5+
let x = [] as [];
6+
let y = x[0];
7+
~
8+
!!! error TS2733: Index '0' is out-of-bounds in tuple of length 0.

tests/baselines/reference/genericCallWithTupleType.errors.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(12,1): error TS2322: Type '[string, number, boolean, boolean]' is not assignable to type '[string, number]'.
22
Types of property 'length' are incompatible.
33
Type '4' is not assignable to type '2'.
4+
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(13,20): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
45
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(14,1): error TS2322: Type '{ a: string; }' is not assignable to type 'string | number'.
56
Type '{ a: string; }' is not assignable to type 'number'.
7+
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(14,11): error TS2733: Index '3' is out-of-bounds in tuple of length 2.
8+
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(15,20): error TS2733: Index '3' is out-of-bounds in tuple of length 2.
69
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(22,14): error TS2322: Type 'number' is not assignable to type 'string'.
710
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(22,17): error TS2322: Type 'string' is not assignable to type 'number'.
811
tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts(23,14): error TS2322: Type '{}' is not assignable to type 'string'.
@@ -11,7 +14,7 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup
1114
Property '1' is missing in type '[{}]'.
1215

1316

14-
==== tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts (7 errors) ====
17+
==== tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTupleType.ts (10 errors) ====
1518
interface I<T, U> {
1619
tuple1: [T, U];
1720
}
@@ -29,11 +32,17 @@ tests/cases/conformance/types/typeRelationships/typeInference/genericCallWithTup
2932
!!! error TS2322: Types of property 'length' are incompatible.
3033
!!! error TS2322: Type '4' is not assignable to type '2'.
3134
var e3 = i1.tuple1[2]; // {}
35+
~
36+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
3237
i1.tuple1[3] = { a: "string" };
3338
~~~~~~~~~~~~
3439
!!! error TS2322: Type '{ a: string; }' is not assignable to type 'string | number'.
3540
!!! error TS2322: Type '{ a: string; }' is not assignable to type 'number'.
41+
~
42+
!!! error TS2733: Index '3' is out-of-bounds in tuple of length 2.
3643
var e4 = i1.tuple1[3]; // {}
44+
~
45+
!!! error TS2733: Index '3' is out-of-bounds in tuple of length 2.
3746
i2.tuple1 = ["foo", 5];
3847
i2.tuple1 = ["foo", "bar"];
3948
i2.tuple1 = [5, "bar"];
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
tests/cases/conformance/types/tuple/indexerWithTuple.ts(11,25): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
2+
tests/cases/conformance/types/tuple/indexerWithTuple.ts(17,27): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
3+
tests/cases/conformance/types/tuple/indexerWithTuple.ts(20,30): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
4+
tests/cases/conformance/types/tuple/indexerWithTuple.ts(28,30): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
5+
6+
7+
==== tests/cases/conformance/types/tuple/indexerWithTuple.ts (4 errors) ====
8+
var strNumTuple: [string, number] = ["foo", 10];
9+
var numTupleTuple: [number, [string, number]] = [10, ["bar", 20]];
10+
var unionTuple1: [number, string| number] = [10, "foo"];
11+
var unionTuple2: [boolean, string| number] = [true, "foo"];
12+
13+
// no error
14+
var idx0 = 0;
15+
var idx1 = 1;
16+
var ele10 = strNumTuple[0]; // string
17+
var ele11 = strNumTuple[1]; // number
18+
var ele12 = strNumTuple[2]; // string | number
19+
~
20+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
21+
var ele13 = strNumTuple[idx0]; // string | number
22+
var ele14 = strNumTuple[idx1]; // string | number
23+
var ele15 = strNumTuple["0"]; // string
24+
var ele16 = strNumTuple["1"]; // number
25+
var strNumTuple1 = numTupleTuple[1]; //[string, number];
26+
var ele17 = numTupleTuple[2]; // number | [string, number]
27+
~
28+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
29+
var eleUnion10 = unionTuple1[0]; // number
30+
var eleUnion11 = unionTuple1[1]; // string | number
31+
var eleUnion12 = unionTuple1[2]; // string | number
32+
~
33+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
34+
var eleUnion13 = unionTuple1[idx0]; // string | number
35+
var eleUnion14 = unionTuple1[idx1]; // string | number
36+
var eleUnion15 = unionTuple1["0"]; // number
37+
var eleUnion16 = unionTuple1["1"]; // string | number
38+
39+
var eleUnion20 = unionTuple2[0]; // boolean
40+
var eleUnion21 = unionTuple2[1]; // string | number
41+
var eleUnion22 = unionTuple2[2]; // string | number | boolean
42+
~
43+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
44+
var eleUnion23 = unionTuple2[idx0]; // string | number | boolean
45+
var eleUnion24 = unionTuple2[idx1]; // string | number | boolean
46+
var eleUnion25 = unionTuple2["0"]; // boolean
47+
var eleUnion26 = unionTuple2["1"]; // string | number
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
tests/cases/conformance/types/tuple/tupleLengthCheck.ts(5,14): error TS2733: Index '2' is out-of-bounds in tuple of length 2.
2+
tests/cases/conformance/types/tuple/tupleLengthCheck.ts(6,14): error TS2733: Index '1000' is out-of-bounds in tuple of length 2.
3+
4+
5+
==== tests/cases/conformance/types/tuple/tupleLengthCheck.ts (2 errors) ====
6+
declare const a: [number, string]
7+
declare const rest: [number, string, ...boolean[]]
8+
9+
const a1 = a[1]
10+
const a2 = a[2]
11+
~
12+
!!! error TS2733: Index '2' is out-of-bounds in tuple of length 2.
13+
const a3 = a[1000]
14+
~~~~
15+
!!! error TS2733: Index '1000' is out-of-bounds in tuple of length 2.
16+
17+
const a4 = rest[1]
18+
const a5 = rest[2]
19+
const a6 = rest[3]
20+
const a7 = rest[1000]
21+

0 commit comments

Comments
 (0)