Skip to content

Commit 32b44ac

Browse files
authored
Merge pull request #29858 from Microsoft/fixContextualRestTuple
Fix contextual types computed from rest parameters
2 parents 17d16d1 + f33c740 commit 32b44ac

6 files changed

+150
-22
lines changed

src/compiler/checker.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -21551,32 +21551,31 @@ namespace ts {
2155121551
}
2155221552
if (signature.hasRestParameter) {
2155321553
const restType = getTypeOfSymbol(signature.parameters[paramCount]);
21554-
if (isTupleType(restType)) {
21555-
if (pos - paramCount < getLengthOfTupleType(restType)) {
21556-
return restType.typeArguments![pos - paramCount];
21557-
}
21558-
return getRestTypeOfTupleType(restType);
21559-
}
21560-
return getIndexTypeOfType(restType, IndexKind.Number);
21554+
const indexType = getLiteralType(pos - paramCount);
21555+
return getIndexedAccessType(restType, indexType);
2156121556
}
2156221557
return undefined;
2156321558
}
2156421559

2156521560
function getRestTypeAtPosition(source: Signature, pos: number): Type {
2156621561
const paramCount = getParameterCount(source);
2156721562
const restType = getEffectiveRestType(source);
21568-
if (restType && pos === paramCount - 1) {
21563+
const nonRestCount = paramCount - (restType ? 1 : 0);
21564+
if (restType && pos === nonRestCount) {
2156921565
return restType;
2157021566
}
21571-
const start = restType ? Math.min(pos, paramCount - 1) : pos;
2157221567
const types = [];
2157321568
const names = [];
21574-
for (let i = start; i < paramCount; i++) {
21569+
for (let i = pos; i < nonRestCount; i++) {
2157521570
types.push(getTypeAtPosition(source, i));
2157621571
names.push(getParameterNameAtPosition(source, i));
2157721572
}
21573+
if (restType) {
21574+
types.push(getIndexedAccessType(restType, numberType));
21575+
names.push(getParameterNameAtPosition(source, nonRestCount));
21576+
}
2157821577
const minArgumentCount = getMinArgumentCount(source);
21579-
const minLength = minArgumentCount < start ? 0 : minArgumentCount - start;
21578+
const minLength = minArgumentCount < pos ? 0 : minArgumentCount - pos;
2158021579
return createTupleType(types, minLength, !!restType, /*readonly*/ false, names);
2158121580
}
2158221581

tests/baselines/reference/restTuplesFromContextualTypes.errors.txt

+20-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error TS2345: Argument of type '(a: number, b: any, ...x: any[]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'.
1+
tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error TS2345: Argument of type '(a: number, b: T[0], ...x: T[number][]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'.
22
Types of parameters 'b' and 'args' are incompatible.
3-
Type 'T' is not assignable to type '[any, ...any[]]'.
4-
Property '0' is missing in type 'any[]' but required in type '[any, ...any[]]'.
3+
Type 'T' is not assignable to type '[T[0], ...T[number][]]'.
4+
Property '0' is missing in type 'any[]' but required in type '[T[0], ...T[number][]]'.
55

66

77
==== tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts (1 errors) ====
@@ -62,10 +62,10 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error
6262
f((a, ...x) => {});
6363
f((a, b, ...x) => {});
6464
~~~~~~~~~~~~~~~~~~
65-
!!! error TS2345: Argument of type '(a: number, b: any, ...x: any[]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'.
65+
!!! error TS2345: Argument of type '(a: number, b: T[0], ...x: T[number][]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'.
6666
!!! error TS2345: Types of parameters 'b' and 'args' are incompatible.
67-
!!! error TS2345: Type 'T' is not assignable to type '[any, ...any[]]'.
68-
!!! error TS2345: Property '0' is missing in type 'any[]' but required in type '[any, ...any[]]'.
67+
!!! error TS2345: Type 'T' is not assignable to type '[T[0], ...T[number][]]'.
68+
!!! error TS2345: Property '0' is missing in type 'any[]' but required in type '[T[0], ...T[number][]]'.
6969
}
7070

7171
// Repro from #25288
@@ -79,4 +79,18 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error
7979

8080
(function foo(...rest){}(1, ''));
8181
take(function(...rest){});
82+
83+
// Repro from #29833
84+
85+
type ArgsUnion = [number, string] | [number, Error];
86+
type TupleUnionFunc = (...params: ArgsUnion) => number;
87+
88+
const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => {
89+
return num;
90+
};
91+
92+
const funcUnionTupleRest: TupleUnionFunc = (...params) => {
93+
const [num, strOrErr] = params;
94+
return num;
95+
};
8296

tests/baselines/reference/restTuplesFromContextualTypes.js

+29
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ declare function take(cb: (a: number, b: string) => void): void;
6868

6969
(function foo(...rest){}(1, ''));
7070
take(function(...rest){});
71+
72+
// Repro from #29833
73+
74+
type ArgsUnion = [number, string] | [number, Error];
75+
type TupleUnionFunc = (...params: ArgsUnion) => number;
76+
77+
const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => {
78+
return num;
79+
};
80+
81+
const funcUnionTupleRest: TupleUnionFunc = (...params) => {
82+
const [num, strOrErr] = params;
83+
return num;
84+
};
7185

7286

7387
//// [restTuplesFromContextualTypes.js]
@@ -274,6 +288,17 @@ take(function () {
274288
rest[_i] = arguments[_i];
275289
}
276290
});
291+
var funcUnionTupleNoRest = function (num, strOrErr) {
292+
return num;
293+
};
294+
var funcUnionTupleRest = function () {
295+
var params = [];
296+
for (var _i = 0; _i < arguments.length; _i++) {
297+
params[_i] = arguments[_i];
298+
}
299+
var num = params[0], strOrErr = params[1];
300+
return num;
301+
};
277302

278303

279304
//// [restTuplesFromContextualTypes.d.ts]
@@ -286,3 +311,7 @@ declare function f3(cb: (x: number, ...args: typeof t3) => void): void;
286311
declare function f4<T extends any[]>(t: T): void;
287312
declare var tuple: [number, string];
288313
declare function take(cb: (a: number, b: string) => void): void;
314+
declare type ArgsUnion = [number, string] | [number, Error];
315+
declare type TupleUnionFunc = (...params: ArgsUnion) => number;
316+
declare const funcUnionTupleNoRest: TupleUnionFunc;
317+
declare const funcUnionTupleRest: TupleUnionFunc;

tests/baselines/reference/restTuplesFromContextualTypes.symbols

+37
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,40 @@ take(function(...rest){});
265265
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 61, 33))
266266
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 68, 14))
267267

268+
// Repro from #29833
269+
270+
type ArgsUnion = [number, string] | [number, Error];
271+
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 68, 26))
272+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
273+
274+
type TupleUnionFunc = (...params: ArgsUnion) => number;
275+
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
276+
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 73, 23))
277+
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 68, 26))
278+
279+
const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => {
280+
>funcUnionTupleNoRest : Symbol(funcUnionTupleNoRest, Decl(restTuplesFromContextualTypes.ts, 75, 5))
281+
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
282+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46))
283+
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 75, 50))
284+
285+
return num;
286+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46))
287+
288+
};
289+
290+
const funcUnionTupleRest: TupleUnionFunc = (...params) => {
291+
>funcUnionTupleRest : Symbol(funcUnionTupleRest, Decl(restTuplesFromContextualTypes.ts, 79, 5))
292+
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
293+
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44))
294+
295+
const [num, strOrErr] = params;
296+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9))
297+
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 80, 13))
298+
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44))
299+
300+
return num;
301+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9))
302+
303+
};
304+

tests/baselines/reference/restTuplesFromContextualTypes.types

+40-5
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,8 @@ function f4<T extends any[]>(t: T) {
332332
f((...x) => {});
333333
>f((...x) => {}) : void
334334
>f : (cb: (x: number, ...args: T) => void) => void
335-
>(...x) => {} : (x: number, ...args: any[]) => void
336-
>x : [number, ...any[]]
335+
>(...x) => {} : (x: number, ...args: T[number][]) => void
336+
>x : [number, ...T[number][]]
337337

338338
f((a, ...x) => {});
339339
>f((a, ...x) => {}) : void
@@ -345,10 +345,10 @@ function f4<T extends any[]>(t: T) {
345345
f((a, b, ...x) => {});
346346
>f((a, b, ...x) => {}) : void
347347
>f : (cb: (x: number, ...args: T) => void) => void
348-
>(a, b, ...x) => {} : (a: number, b: any, ...x: any[]) => void
348+
>(a, b, ...x) => {} : (a: number, b: T[0], ...x: T[number][]) => void
349349
>a : number
350-
>b : any
351-
>x : any[]
350+
>b : T[0]
351+
>x : T[number][]
352352
}
353353

354354
// Repro from #25288
@@ -389,3 +389,38 @@ take(function(...rest){});
389389
>function(...rest){} : (a: number, b: string) => void
390390
>rest : [number, string]
391391

392+
// Repro from #29833
393+
394+
type ArgsUnion = [number, string] | [number, Error];
395+
>ArgsUnion : ArgsUnion
396+
397+
type TupleUnionFunc = (...params: ArgsUnion) => number;
398+
>TupleUnionFunc : TupleUnionFunc
399+
>params : ArgsUnion
400+
401+
const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => {
402+
>funcUnionTupleNoRest : TupleUnionFunc
403+
>(num, strOrErr) => { return num;} : (num: number, strOrErr: string | Error) => number
404+
>num : number
405+
>strOrErr : string | Error
406+
407+
return num;
408+
>num : number
409+
410+
};
411+
412+
const funcUnionTupleRest: TupleUnionFunc = (...params) => {
413+
>funcUnionTupleRest : TupleUnionFunc
414+
>(...params) => { const [num, strOrErr] = params; return num;} : (...params: ArgsUnion) => number
415+
>params : ArgsUnion
416+
417+
const [num, strOrErr] = params;
418+
>num : number
419+
>strOrErr : string | Error
420+
>params : ArgsUnion
421+
422+
return num;
423+
>num : number
424+
425+
};
426+

tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts

+14
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,17 @@ declare function take(cb: (a: number, b: string) => void): void;
7070

7171
(function foo(...rest){}(1, ''));
7272
take(function(...rest){});
73+
74+
// Repro from #29833
75+
76+
type ArgsUnion = [number, string] | [number, Error];
77+
type TupleUnionFunc = (...params: ArgsUnion) => number;
78+
79+
const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => {
80+
return num;
81+
};
82+
83+
const funcUnionTupleRest: TupleUnionFunc = (...params) => {
84+
const [num, strOrErr] = params;
85+
return num;
86+
};

0 commit comments

Comments
 (0)