Skip to content

Commit 3073b52

Browse files
authored
Extend isTupleLikeType to also check if .length is a number literal type (#52617)
1 parent 34f6e10 commit 3073b52

File tree

6 files changed

+92
-4
lines changed

6 files changed

+92
-4
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23303,7 +23303,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2330323303
}
2330423304

2330523305
function isTupleLikeType(type: Type): boolean {
23306-
return isTupleType(type) || !!getPropertyOfType(type, "0" as __String);
23306+
let lengthType;
23307+
return isTupleType(type) ||
23308+
!!getPropertyOfType(type, "0" as __String) ||
23309+
isArrayLikeType(type) && !!(lengthType = getTypeOfPropertyOfType(type, "length" as __String)) && everyType(lengthType, t => !!(t.flags & TypeFlags.NumberLiteral));
2330723310
}
2330823311

2330923312
function isArrayOrTupleLikeType(type: Type): boolean {

tests/baselines/reference/contextualTypeWithTuple.errors.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,15 @@ contextualTypeWithTuple.ts(25,1): error TS2322: Type '[number, string | number]'
6868
!!! error TS2322: Type '[number, string | number]' is not assignable to type '[number, string]'.
6969
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
7070
!!! error TS2322: Type 'string | number' is not assignable to type 'string'.
71-
!!! error TS2322: Type 'number' is not assignable to type 'string'.
71+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
72+
73+
// repro from #29311
74+
type test1 = [...number[]]
75+
type fixed1 = test1 & { length: 2 }
76+
let var1: fixed1 = [0, 0]
77+
78+
// #52551
79+
type EmptyTuple = []
80+
interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; }
81+
const withExtra: MyEmptyTuple = []
82+

tests/baselines/reference/contextualTypeWithTuple.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,18 @@ var strStrTuple: [string, string] = ["foo", "bar", 5];
2525
unionTuple = unionTuple1;
2626
unionTuple = unionTuple2;
2727
unionTuple2 = unionTuple;
28-
numStrTuple = unionTuple3;
28+
numStrTuple = unionTuple3;
29+
30+
// repro from #29311
31+
type test1 = [...number[]]
32+
type fixed1 = test1 & { length: 2 }
33+
let var1: fixed1 = [0, 0]
34+
35+
// #52551
36+
type EmptyTuple = []
37+
interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; }
38+
const withExtra: MyEmptyTuple = []
39+
2940

3041
//// [contextualTypeWithTuple.js]
3142
// no error
@@ -58,3 +69,5 @@ unionTuple = unionTuple1;
5869
unionTuple = unionTuple2;
5970
unionTuple2 = unionTuple;
6071
numStrTuple = unionTuple3;
72+
var var1 = [0, 0];
73+
var withExtra = [];

tests/baselines/reference/contextualTypeWithTuple.symbols

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,29 @@ numStrTuple = unionTuple3;
8282
>numStrTuple : Symbol(numStrTuple, Decl(contextualTypeWithTuple.ts, 1, 3))
8383
>unionTuple3 : Symbol(unionTuple3, Decl(contextualTypeWithTuple.ts, 11, 3))
8484

85+
// repro from #29311
86+
type test1 = [...number[]]
87+
>test1 : Symbol(test1, Decl(contextualTypeWithTuple.ts, 24, 26))
88+
89+
type fixed1 = test1 & { length: 2 }
90+
>fixed1 : Symbol(fixed1, Decl(contextualTypeWithTuple.ts, 27, 26))
91+
>test1 : Symbol(test1, Decl(contextualTypeWithTuple.ts, 24, 26))
92+
>length : Symbol(length, Decl(contextualTypeWithTuple.ts, 28, 23))
93+
94+
let var1: fixed1 = [0, 0]
95+
>var1 : Symbol(var1, Decl(contextualTypeWithTuple.ts, 29, 3))
96+
>fixed1 : Symbol(fixed1, Decl(contextualTypeWithTuple.ts, 27, 26))
97+
98+
// #52551
99+
type EmptyTuple = []
100+
>EmptyTuple : Symbol(EmptyTuple, Decl(contextualTypeWithTuple.ts, 29, 25))
101+
102+
interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; }
103+
>MyEmptyTuple : Symbol(MyEmptyTuple, Decl(contextualTypeWithTuple.ts, 32, 20))
104+
>EmptyTuple : Symbol(EmptyTuple, Decl(contextualTypeWithTuple.ts, 29, 25))
105+
>extraInfo : Symbol(MyEmptyTuple.extraInfo, Decl(contextualTypeWithTuple.ts, 33, 43))
106+
107+
const withExtra: MyEmptyTuple = []
108+
>withExtra : Symbol(withExtra, Decl(contextualTypeWithTuple.ts, 34, 5))
109+
>MyEmptyTuple : Symbol(MyEmptyTuple, Decl(contextualTypeWithTuple.ts, 32, 20))
110+

tests/baselines/reference/contextualTypeWithTuple.types

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,28 @@ numStrTuple = unionTuple3;
128128
>numStrTuple : [number, string]
129129
>unionTuple3 : [number, string | number]
130130

131+
// repro from #29311
132+
type test1 = [...number[]]
133+
>test1 : number[]
134+
135+
type fixed1 = test1 & { length: 2 }
136+
>fixed1 : test1 & { length: 2; }
137+
>length : 2
138+
139+
let var1: fixed1 = [0, 0]
140+
>var1 : fixed1
141+
>[0, 0] : [number, number]
142+
>0 : 0
143+
>0 : 0
144+
145+
// #52551
146+
type EmptyTuple = []
147+
>EmptyTuple : []
148+
149+
interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; }
150+
>extraInfo : any
151+
152+
const withExtra: MyEmptyTuple = []
153+
>withExtra : MyEmptyTuple
154+
>[] : []
155+

tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,14 @@ var strStrTuple: [string, string] = ["foo", "bar", 5];
2222
unionTuple = unionTuple1;
2323
unionTuple = unionTuple2;
2424
unionTuple2 = unionTuple;
25-
numStrTuple = unionTuple3;
25+
numStrTuple = unionTuple3;
26+
27+
// repro from #29311
28+
type test1 = [...number[]]
29+
type fixed1 = test1 & { length: 2 }
30+
let var1: fixed1 = [0, 0]
31+
32+
// #52551
33+
type EmptyTuple = []
34+
interface MyEmptyTuple extends EmptyTuple { extraInfo?: any; }
35+
const withExtra: MyEmptyTuple = []

0 commit comments

Comments
 (0)