Skip to content

Commit 98314d7

Browse files
authored
Use unexpanded parameter list in serialization when the expanded list has a non-trailing variadic position (microsoft#40556)
1 parent d40663f commit 98314d7

6 files changed

+67
-34
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5101,7 +5101,9 @@ namespace ts {
51015101
typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context));
51025102
}
51035103

5104-
const parameters = getExpandedParameters(signature, /*skipUnionExpanding*/ true)[0].map(parameter => symbolToParameterDeclaration(parameter, context, kind === SyntaxKind.Constructor, options?.privateSymbolVisitor, options?.bundledImports));
5104+
const expandedParams = getExpandedParameters(signature, /*skipUnionExpanding*/ true)[0];
5105+
// If the expanded parameter list had a variadic in a non-trailing position, don't expand it
5106+
const parameters = (some(expandedParams, p => p !== expandedParams[expandedParams.length - 1] && !!(getCheckFlags(p) & CheckFlags.RestParameter)) ? signature.parameters : expandedParams).map(parameter => symbolToParameterDeclaration(parameter, context, kind === SyntaxKind.Constructor, options?.privateSymbolVisitor, options?.bundledImports));
51055107
if (signature.thisParameter) {
51065108
const thisParameter = symbolToParameterDeclaration(signature.thisParameter, context);
51075109
parameters.unshift(thisParameter);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [declarationEmitTupleRestSignatureLeadingVariadic.ts]
2+
const f = <TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]): void => {};
3+
4+
//// [declarationEmitTupleRestSignatureLeadingVariadic.js]
5+
var f = function () {
6+
var args = [];
7+
for (var _i = 0; _i < arguments.length; _i++) {
8+
args[_i] = arguments[_i];
9+
}
10+
};
11+
12+
13+
//// [declarationEmitTupleRestSignatureLeadingVariadic.d.ts]
14+
declare const f: <TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]) => void;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/declarationEmitTupleRestSignatureLeadingVariadic.ts ===
2+
const f = <TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]): void => {};
3+
>f : Symbol(f, Decl(declarationEmitTupleRestSignatureLeadingVariadic.ts, 0, 5))
4+
>TFirstArgs : Symbol(TFirstArgs, Decl(declarationEmitTupleRestSignatureLeadingVariadic.ts, 0, 11))
5+
>TLastArg : Symbol(TLastArg, Decl(declarationEmitTupleRestSignatureLeadingVariadic.ts, 0, 36))
6+
>args : Symbol(args, Decl(declarationEmitTupleRestSignatureLeadingVariadic.ts, 0, 47))
7+
>TFirstArgs : Symbol(TFirstArgs, Decl(declarationEmitTupleRestSignatureLeadingVariadic.ts, 0, 11))
8+
>TLastArg : Symbol(TLastArg, Decl(declarationEmitTupleRestSignatureLeadingVariadic.ts, 0, 36))
9+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== tests/cases/compiler/declarationEmitTupleRestSignatureLeadingVariadic.ts ===
2+
const f = <TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]): void => {};
3+
>f : <TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]) => void
4+
><TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]): void => {} : <TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]) => void
5+
>args : [...TFirstArgs, TLastArg]
6+

tests/baselines/reference/variadicTuples1.types

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ function foo2(t1: [number, string], t2: [boolean], a1: number[]) {
216216
}
217217

218218
declare function foo3<T extends unknown[]>(x: number, ...args: [...T, number]): T;
219-
>foo3 : <T extends unknown[]>(x: number, ...args_0: T, args_1: number) => T
219+
>foo3 : <T extends unknown[]>(x: number, ...args: [...T, number]) => T
220220
>x : number
221221
>args : [...T, number]
222222

@@ -226,21 +226,21 @@ function foo4<U extends unknown[]>(u: U) {
226226

227227
foo3(1, 2);
228228
>foo3(1, 2) : []
229-
>foo3 : <T extends unknown[]>(x: number, ...args_0: T, args_1: number) => T
229+
>foo3 : <T extends unknown[]>(x: number, ...args: [...T, number]) => T
230230
>1 : 1
231231
>2 : 2
232232

233233
foo3(1, 'hello', true, 2);
234234
>foo3(1, 'hello', true, 2) : [string, boolean]
235-
>foo3 : <T extends unknown[]>(x: number, ...args_0: T, args_1: number) => T
235+
>foo3 : <T extends unknown[]>(x: number, ...args: [...T, number]) => T
236236
>1 : 1
237237
>'hello' : "hello"
238238
>true : true
239239
>2 : 2
240240

241241
foo3(1, ...u, 'hi', 2);
242242
>foo3(1, ...u, 'hi', 2) : [...U, string]
243-
>foo3 : <T extends unknown[]>(x: number, ...args_0: T, args_1: number) => T
243+
>foo3 : <T extends unknown[]>(x: number, ...args: [...T, number]) => T
244244
>1 : 1
245245
>...u : unknown
246246
>u : U
@@ -249,7 +249,7 @@ function foo4<U extends unknown[]>(u: U) {
249249

250250
foo3(1);
251251
>foo3(1) : unknown[]
252-
>foo3 : <T extends unknown[]>(x: number, ...args_0: T, args_1: number) => T
252+
>foo3 : <T extends unknown[]>(x: number, ...args: [...T, number]) => T
253253
>1 : 1
254254
}
255255

@@ -991,16 +991,16 @@ type R36 = DropLast<readonly []>;
991991
// Inference to [...T, ...U] with implied arity for T
992992

993993
function curry<T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) {
994-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
995-
>f : (...args_0: T, ...args_1: U) => R
994+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
995+
>f : (...args: [...T, ...U]) => R
996996
>args : [...T, ...U]
997997
>a : T
998998

999999
return (...b: U) => f(...a, ...b);
10001000
>(...b: U) => f(...a, ...b) : (...b: U) => R
10011001
>b : U
10021002
>f(...a, ...b) : R
1003-
>f : (...args_0: T, ...args_1: U) => R
1003+
>f : (...args: [...T, ...U]) => R
10041004
>...a : unknown
10051005
>a : T
10061006
>...b : unknown
@@ -1019,28 +1019,28 @@ const fn1 = (a: number, b: string, c: boolean, d: string[]) => 0;
10191019
const c0 = curry(fn1); // (a: number, b: string, c: boolean, d: string[]) => number
10201020
>c0 : (a: number, b: string, c: boolean, d: string[]) => number
10211021
>curry(fn1) : (a: number, b: string, c: boolean, d: string[]) => number
1022-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1022+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10231023
>fn1 : (a: number, b: string, c: boolean, d: string[]) => number
10241024

10251025
const c1 = curry(fn1, 1); // (b: string, c: boolean, d: string[]) => number
10261026
>c1 : (b: string, c: boolean, d: string[]) => number
10271027
>curry(fn1, 1) : (b: string, c: boolean, d: string[]) => number
1028-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1028+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10291029
>fn1 : (a: number, b: string, c: boolean, d: string[]) => number
10301030
>1 : 1
10311031

10321032
const c2 = curry(fn1, 1, 'abc'); // (c: boolean, d: string[]) => number
10331033
>c2 : (c: boolean, d: string[]) => number
10341034
>curry(fn1, 1, 'abc') : (c: boolean, d: string[]) => number
1035-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1035+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10361036
>fn1 : (a: number, b: string, c: boolean, d: string[]) => number
10371037
>1 : 1
10381038
>'abc' : "abc"
10391039

10401040
const c3 = curry(fn1, 1, 'abc', true); // (d: string[]) => number
10411041
>c3 : (d: string[]) => number
10421042
>curry(fn1, 1, 'abc', true) : (d: string[]) => number
1043-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1043+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10441044
>fn1 : (a: number, b: string, c: boolean, d: string[]) => number
10451045
>1 : 1
10461046
>'abc' : "abc"
@@ -1049,7 +1049,7 @@ const c3 = curry(fn1, 1, 'abc', true); // (d: string[]) => number
10491049
const c4 = curry(fn1, 1, 'abc', true, ['x', 'y']); // () => number
10501050
>c4 : () => number
10511051
>curry(fn1, 1, 'abc', true, ['x', 'y']) : () => number
1052-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1052+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10531053
>fn1 : (a: number, b: string, c: boolean, d: string[]) => number
10541054
>1 : 1
10551055
>'abc' : "abc"
@@ -1069,28 +1069,28 @@ const fn2 = (x: number, b: boolean, ...args: string[]) => 0;
10691069
const c10 = curry(fn2); // (x: number, b: boolean, ...args: string[]) => number
10701070
>c10 : (x: number, b: boolean, ...args: string[]) => number
10711071
>curry(fn2) : (x: number, b: boolean, ...args: string[]) => number
1072-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1072+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10731073
>fn2 : (x: number, b: boolean, ...args: string[]) => number
10741074

10751075
const c11 = curry(fn2, 1); // (b: boolean, ...args: string[]) => number
10761076
>c11 : (b: boolean, ...args: string[]) => number
10771077
>curry(fn2, 1) : (b: boolean, ...args: string[]) => number
1078-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1078+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10791079
>fn2 : (x: number, b: boolean, ...args: string[]) => number
10801080
>1 : 1
10811081

10821082
const c12 = curry(fn2, 1, true); // (...args: string[]) => number
10831083
>c12 : (...b: string[]) => number
10841084
>curry(fn2, 1, true) : (...b: string[]) => number
1085-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1085+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10861086
>fn2 : (x: number, b: boolean, ...args: string[]) => number
10871087
>1 : 1
10881088
>true : true
10891089

10901090
const c13 = curry(fn2, 1, true, 'abc', 'def'); // (...args: string[]) => number
10911091
>c13 : (...b: string[]) => number
10921092
>curry(fn2, 1, true, 'abc', 'def') : (...b: string[]) => number
1093-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1093+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
10941094
>fn2 : (x: number, b: boolean, ...args: string[]) => number
10951095
>1 : 1
10961096
>true : true
@@ -1106,37 +1106,37 @@ const fn3 = (...args: string[]) => 0;
11061106
const c20 = curry(fn3); // (...args: string[]) => number
11071107
>c20 : (...b: string[]) => number
11081108
>curry(fn3) : (...b: string[]) => number
1109-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1109+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
11101110
>fn3 : (...args: string[]) => number
11111111

11121112
const c21 = curry(fn3, 'abc', 'def'); // (...args: string[]) => number
11131113
>c21 : (...b: string[]) => number
11141114
>curry(fn3, 'abc', 'def') : (...b: string[]) => number
1115-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1115+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
11161116
>fn3 : (...args: string[]) => number
11171117
>'abc' : "abc"
11181118
>'def' : "def"
11191119

11201120
const c22 = curry(fn3, ...sa); // (...args: string[]) => number
11211121
>c22 : (...b: string[]) => number
11221122
>curry(fn3, ...sa) : (...b: string[]) => number
1123-
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, ...a: T) => (...b: U) => R
1123+
>curry : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, ...a: T) => (...b: U) => R
11241124
>fn3 : (...args: string[]) => number
11251125
>...sa : string
11261126
>sa : string[]
11271127

11281128
// No inference to [...T, ...U] when there is no implied arity
11291129

11301130
function curry2<T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, t: [...T], u: [...U]) {
1131-
>curry2 : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, t: [...T], u: [...U]) => R
1132-
>f : (...args_0: T, ...args_1: U) => R
1131+
>curry2 : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, t: [...T], u: [...U]) => R
1132+
>f : (...args: [...T, ...U]) => R
11331133
>args : [...T, ...U]
11341134
>t : [...T]
11351135
>u : [...U]
11361136

11371137
return f(...t, ...u);
11381138
>f(...t, ...u) : R
1139-
>f : (...args_0: T, ...args_1: U) => R
1139+
>f : (...args: [...T, ...U]) => R
11401140
>...t : T[number]
11411141
>t : [...T]
11421142
>...u : U[number]
@@ -1151,7 +1151,7 @@ declare function fn10(a: string, b: number, c: boolean): string[];
11511151

11521152
curry2(fn10, ['hello', 42], [true]);
11531153
>curry2(fn10, ['hello', 42], [true]) : string[]
1154-
>curry2 : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, t: [...T], u: [...U]) => R
1154+
>curry2 : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, t: [...T], u: [...U]) => R
11551155
>fn10 : (a: string, b: number, c: boolean) => string[]
11561156
>['hello', 42] : [string, number]
11571157
>'hello' : "hello"
@@ -1161,7 +1161,7 @@ curry2(fn10, ['hello', 42], [true]);
11611161

11621162
curry2(fn10, ['hello'], [42, true]);
11631163
>curry2(fn10, ['hello'], [42, true]) : string[]
1164-
>curry2 : <T extends unknown[], U extends unknown[], R>(f: (...args_0: T, ...args_1: U) => R, t: [...T], u: [...U]) => R
1164+
>curry2 : <T extends unknown[], U extends unknown[], R>(f: (...args: [...T, ...U]) => R, t: [...T], u: [...U]) => R
11651165
>fn10 : (a: string, b: number, c: boolean) => string[]
11661166
>['hello'] : [string]
11671167
>'hello' : "hello"
@@ -1223,13 +1223,13 @@ ft(['a', 'b'], ['c', 'd', 42])
12231223
// Last argument is contextually typed
12241224

12251225
declare function call<T extends unknown[], R>(...args: [...T, (...args: T) => R]): [T, R];
1226-
>call : <T extends unknown[], R>(...args_0: T, args_1: (...args: T) => R) => [T, R]
1226+
>call : <T extends unknown[], R>(...args: [...T, (...args: T) => R]) => [T, R]
12271227
>args : [...T, (...args: T) => R]
12281228
>args : T
12291229

12301230
call('hello', 32, (a, b) => 42);
12311231
>call('hello', 32, (a, b) => 42) : [[string, number], number]
1232-
>call : <T extends unknown[], R>(...args_0: T, args_1: (...args: T) => R) => [T, R]
1232+
>call : <T extends unknown[], R>(...args: [...T, (...args: T) => R]) => [T, R]
12331233
>'hello' : "hello"
12341234
>32 : 32
12351235
>(a, b) => 42 : (a: string, b: number) => number
@@ -1242,7 +1242,7 @@ call('hello', 32, (a, b) => 42);
12421242

12431243
call(...sa, (...x) => 42);
12441244
>call(...sa, (...x) => 42) : [(string | ((...x: any[]) => number))[], number]
1245-
>call : <T extends unknown[], R>(...args_0: T, args_1: (...args: T) => R) => [T, R]
1245+
>call : <T extends unknown[], R>(...args: [...T, (...args: T) => R]) => [T, R]
12461246
>...sa : string
12471247
>sa : string[]
12481248
>(...x) => 42 : (...x: any[]) => number
@@ -1359,28 +1359,28 @@ declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z
13591359
>z : boolean | undefined
13601360

13611361
function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
1362-
>callApi : <T extends unknown[] = [], U = void>(method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U
1363-
>method : (...args_0: T, args_1: object) => U
1362+
>callApi : <T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) => (...args_0: T) => U
1363+
>method : (...args: [...T, object]) => U
13641364
>args : [...T, object]
13651365

13661366
return (...args: [...T]) => method(...args, {});
13671367
>(...args: [...T]) => method(...args, {}) : (...args_0: T) => U
13681368
>args : [...T]
13691369
>method(...args, {}) : U
1370-
>method : (...args_0: T, args_1: object) => U
1370+
>method : (...args: [...T, object]) => U
13711371
>...args : T[number]
13721372
>args : [...T]
13731373
>{} : {}
13741374
}
13751375

13761376
callApi(getUser);
13771377
>callApi(getUser) : (id: string) => string
1378-
>callApi : <T extends unknown[] = [], U = void>(method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U
1378+
>callApi : <T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) => (...args_0: T) => U
13791379
>getUser : (id: string, options?: { x?: string | undefined; } | undefined) => string
13801380

13811381
callApi(getOrgUser);
13821382
>callApi(getOrgUser) : (id: string, orgId: number) => void
1383-
>callApi : <T extends unknown[] = [], U = void>(method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U
1383+
>callApi : <T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) => (...args_0: T) => U
13841384
>getOrgUser : (id: string, orgId: number, options?: { y?: number | undefined; z?: boolean | undefined; } | undefined) => void
13851385

13861386
// Repro from #40235
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @declaration: true
2+
const f = <TFirstArgs extends any[], TLastArg>(...args: [...TFirstArgs, TLastArg]): void => {};

0 commit comments

Comments
 (0)