Skip to content

Commit db79030

Browse files
authored
Support variadic tuple inference from trailing optional to non-optional (#39614)
* Permit variadic tuple inference from trailing optional to non-optional * Add tests
1 parent b6f09cc commit db79030

File tree

6 files changed

+143
-4
lines changed

6 files changed

+143
-4
lines changed

src/compiler/checker.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -18501,8 +18501,8 @@ namespace ts {
1850118501
return restType && createArrayType(restType);
1850218502
}
1850318503

18504-
function getEndLengthOfType(type: Type) {
18505-
return isTupleType(type) ? getTypeReferenceArity(type) - findLastIndex(type.target.elementFlags, f => !(f & ElementFlags.Required)) - 1 : 0;
18504+
function getEndLengthOfType(type: Type, flags: ElementFlags) {
18505+
return isTupleType(type) ? getTypeReferenceArity(type) - findLastIndex(type.target.elementFlags, f => !(f & flags)) - 1 : 0;
1850618506
}
1850718507

1850818508
function getElementTypeOfSliceOfTupleType(type: TupleTypeReference, index: number, endSkipCount = 0, writing = false) {
@@ -19763,8 +19763,8 @@ namespace ts {
1976319763
const sourceRestType = !isTupleType(source) || sourceArity > 0 && source.target.elementFlags[sourceArity - 1] & ElementFlags.Rest ?
1976419764
getTypeArguments(source)[sourceArity - 1] : undefined;
1976519765
const endLength = !(target.target.combinedFlags & ElementFlags.Variable) ? 0 :
19766-
sourceRestType ? getEndLengthOfType(target) :
19767-
Math.min(getEndLengthOfType(source), getEndLengthOfType(target));
19766+
sourceRestType ? getEndLengthOfType(target, ElementFlags.Required) :
19767+
Math.min(getEndLengthOfType(source, ElementFlags.Required | ElementFlags.Optional), getEndLengthOfType(target, ElementFlags.Required));
1976819768
const sourceEndLength = sourceRestType ? 0 : endLength;
1976919769
// Infer between starting fixed elements.
1977019770
for (let i = 0; i < startLength; i++) {

tests/baselines/reference/variadicTuples1.errors.txt

+13
Original file line numberDiff line numberDiff line change
@@ -473,4 +473,17 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(342,19): error TS2322: Ty
473473

474474
declare const a: Desc<[string, number, boolean], object>;
475475
const b = a.bind("", 1); // Desc<[boolean], object>
476+
477+
// Repro from #39607
478+
479+
declare function getUser(id: string, options?: { x?: string }): string;
480+
481+
declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void;
482+
483+
function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
484+
return (...args: [...T]) => method(...args, {});
485+
}
486+
487+
callApi(getUser);
488+
callApi(getOrgUser);
476489

tests/baselines/reference/variadicTuples1.js

+32
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,19 @@ interface Desc<A extends unknown[], T> {
361361

362362
declare const a: Desc<[string, number, boolean], object>;
363363
const b = a.bind("", 1); // Desc<[boolean], object>
364+
365+
// Repro from #39607
366+
367+
declare function getUser(id: string, options?: { x?: string }): string;
368+
369+
declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void;
370+
371+
function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
372+
return (...args: [...T]) => method(...args, {});
373+
}
374+
375+
callApi(getUser);
376+
callApi(getOrgUser);
364377

365378

366379
//// [variadicTuples1.js]
@@ -568,6 +581,17 @@ function f23(args) {
568581
var v3 = f22(["foo", 42]); // [string]
569582
}
570583
var b = a.bind("", 1); // Desc<[boolean], object>
584+
function callApi(method) {
585+
return function () {
586+
var args = [];
587+
for (var _i = 0; _i < arguments.length; _i++) {
588+
args[_i] = arguments[_i];
589+
}
590+
return method.apply(void 0, __spreadArrays(args, [{}]));
591+
};
592+
}
593+
callApi(getUser);
594+
callApi(getOrgUser);
571595

572596

573597
//// [variadicTuples1.d.ts]
@@ -720,3 +744,11 @@ interface Desc<A extends unknown[], T> {
720744
}
721745
declare const a: Desc<[string, number, boolean], object>;
722746
declare const b: Desc<[boolean], object>;
747+
declare function getUser(id: string, options?: {
748+
x?: string;
749+
}): string;
750+
declare function getOrgUser(id: string, orgId: number, options?: {
751+
y?: number;
752+
z?: boolean;
753+
}): void;
754+
declare function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U): (...args_0: T) => U;

tests/baselines/reference/variadicTuples1.symbols

+40
Original file line numberDiff line numberDiff line change
@@ -1244,3 +1244,43 @@ const b = a.bind("", 1); // Desc<[boolean], object>
12441244
>a : Symbol(a, Decl(variadicTuples1.ts, 360, 13))
12451245
>bind : Symbol(Desc.bind, Decl(variadicTuples1.ts, 356, 34))
12461246

1247+
// Repro from #39607
1248+
1249+
declare function getUser(id: string, options?: { x?: string }): string;
1250+
>getUser : Symbol(getUser, Decl(variadicTuples1.ts, 361, 24))
1251+
>id : Symbol(id, Decl(variadicTuples1.ts, 365, 25))
1252+
>options : Symbol(options, Decl(variadicTuples1.ts, 365, 36))
1253+
>x : Symbol(x, Decl(variadicTuples1.ts, 365, 48))
1254+
1255+
declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void;
1256+
>getOrgUser : Symbol(getOrgUser, Decl(variadicTuples1.ts, 365, 71))
1257+
>id : Symbol(id, Decl(variadicTuples1.ts, 367, 28))
1258+
>orgId : Symbol(orgId, Decl(variadicTuples1.ts, 367, 39))
1259+
>options : Symbol(options, Decl(variadicTuples1.ts, 367, 54))
1260+
>y : Symbol(y, Decl(variadicTuples1.ts, 367, 66))
1261+
>z : Symbol(z, Decl(variadicTuples1.ts, 367, 78))
1262+
1263+
function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
1264+
>callApi : Symbol(callApi, Decl(variadicTuples1.ts, 367, 100))
1265+
>T : Symbol(T, Decl(variadicTuples1.ts, 369, 17))
1266+
>U : Symbol(U, Decl(variadicTuples1.ts, 369, 42))
1267+
>method : Symbol(method, Decl(variadicTuples1.ts, 369, 53))
1268+
>args : Symbol(args, Decl(variadicTuples1.ts, 369, 62))
1269+
>T : Symbol(T, Decl(variadicTuples1.ts, 369, 17))
1270+
>U : Symbol(U, Decl(variadicTuples1.ts, 369, 42))
1271+
1272+
return (...args: [...T]) => method(...args, {});
1273+
>args : Symbol(args, Decl(variadicTuples1.ts, 370, 12))
1274+
>T : Symbol(T, Decl(variadicTuples1.ts, 369, 17))
1275+
>method : Symbol(method, Decl(variadicTuples1.ts, 369, 53))
1276+
>args : Symbol(args, Decl(variadicTuples1.ts, 370, 12))
1277+
}
1278+
1279+
callApi(getUser);
1280+
>callApi : Symbol(callApi, Decl(variadicTuples1.ts, 367, 100))
1281+
>getUser : Symbol(getUser, Decl(variadicTuples1.ts, 361, 24))
1282+
1283+
callApi(getOrgUser);
1284+
>callApi : Symbol(callApi, Decl(variadicTuples1.ts, 367, 100))
1285+
>getOrgUser : Symbol(getOrgUser, Decl(variadicTuples1.ts, 365, 71))
1286+

tests/baselines/reference/variadicTuples1.types

+41
Original file line numberDiff line numberDiff line change
@@ -1279,3 +1279,44 @@ const b = a.bind("", 1); // Desc<[boolean], object>
12791279
>"" : ""
12801280
>1 : 1
12811281

1282+
// Repro from #39607
1283+
1284+
declare function getUser(id: string, options?: { x?: string }): string;
1285+
>getUser : (id: string, options?: { x?: string | undefined; } | undefined) => string
1286+
>id : string
1287+
>options : { x?: string | undefined; } | undefined
1288+
>x : string | undefined
1289+
1290+
declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void;
1291+
>getOrgUser : (id: string, orgId: number, options?: { y?: number | undefined; z?: boolean | undefined; } | undefined) => void
1292+
>id : string
1293+
>orgId : number
1294+
>options : { y?: number | undefined; z?: boolean | undefined; } | undefined
1295+
>y : number | undefined
1296+
>z : boolean | undefined
1297+
1298+
function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
1299+
>callApi : <T extends unknown[] = [], U = void>(method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U
1300+
>method : (...args_0: T, args_1: object) => U
1301+
>args : [...T, object]
1302+
1303+
return (...args: [...T]) => method(...args, {});
1304+
>(...args: [...T]) => method(...args, {}) : (...args_0: T) => U
1305+
>args : [...T]
1306+
>method(...args, {}) : U
1307+
>method : (...args_0: T, args_1: object) => U
1308+
>...args : T[number]
1309+
>args : [...T]
1310+
>{} : {}
1311+
}
1312+
1313+
callApi(getUser);
1314+
>callApi(getUser) : (id: string) => string
1315+
>callApi : <T extends unknown[] = [], U = void>(method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U
1316+
>getUser : (id: string, options?: { x?: string | undefined; } | undefined) => string
1317+
1318+
callApi(getOrgUser);
1319+
>callApi(getOrgUser) : (id: string, orgId: number) => void
1320+
>callApi : <T extends unknown[] = [], U = void>(method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U
1321+
>getOrgUser : (id: string, orgId: number, options?: { y?: number | undefined; z?: boolean | undefined; } | undefined) => void
1322+

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

+13
Original file line numberDiff line numberDiff line change
@@ -363,3 +363,16 @@ interface Desc<A extends unknown[], T> {
363363

364364
declare const a: Desc<[string, number, boolean], object>;
365365
const b = a.bind("", 1); // Desc<[boolean], object>
366+
367+
// Repro from #39607
368+
369+
declare function getUser(id: string, options?: { x?: string }): string;
370+
371+
declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void;
372+
373+
function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
374+
return (...args: [...T]) => method(...args, {});
375+
}
376+
377+
callApi(getUser);
378+
callApi(getOrgUser);

0 commit comments

Comments
 (0)