diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ef279c287581a..e0dea081f67e8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18501,8 +18501,8 @@ namespace ts { return restType && createArrayType(restType); } - function getEndLengthOfType(type: Type) { - return isTupleType(type) ? getTypeReferenceArity(type) - findLastIndex(type.target.elementFlags, f => !(f & ElementFlags.Required)) - 1 : 0; + function getEndLengthOfType(type: Type, flags: ElementFlags) { + return isTupleType(type) ? getTypeReferenceArity(type) - findLastIndex(type.target.elementFlags, f => !(f & flags)) - 1 : 0; } function getElementTypeOfSliceOfTupleType(type: TupleTypeReference, index: number, endSkipCount = 0, writing = false) { @@ -19763,8 +19763,8 @@ namespace ts { const sourceRestType = !isTupleType(source) || sourceArity > 0 && source.target.elementFlags[sourceArity - 1] & ElementFlags.Rest ? getTypeArguments(source)[sourceArity - 1] : undefined; const endLength = !(target.target.combinedFlags & ElementFlags.Variable) ? 0 : - sourceRestType ? getEndLengthOfType(target) : - Math.min(getEndLengthOfType(source), getEndLengthOfType(target)); + sourceRestType ? getEndLengthOfType(target, ElementFlags.Required) : + Math.min(getEndLengthOfType(source, ElementFlags.Required | ElementFlags.Optional), getEndLengthOfType(target, ElementFlags.Required)); const sourceEndLength = sourceRestType ? 0 : endLength; // Infer between starting fixed elements. for (let i = 0; i < startLength; i++) { diff --git a/tests/baselines/reference/variadicTuples1.errors.txt b/tests/baselines/reference/variadicTuples1.errors.txt index a50b0671fdeeb..863bc431f6f4b 100644 --- a/tests/baselines/reference/variadicTuples1.errors.txt +++ b/tests/baselines/reference/variadicTuples1.errors.txt @@ -473,4 +473,17 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(342,19): error TS2322: Ty declare const a: Desc<[string, number, boolean], object>; const b = a.bind("", 1); // Desc<[boolean], object> + + // Repro from #39607 + + declare function getUser(id: string, options?: { x?: string }): string; + + declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void; + + function callApi(method: (...args: [...T, object]) => U) { + return (...args: [...T]) => method(...args, {}); + } + + callApi(getUser); + callApi(getOrgUser); \ No newline at end of file diff --git a/tests/baselines/reference/variadicTuples1.js b/tests/baselines/reference/variadicTuples1.js index be8cf4838eea3..b75ffcb37009d 100644 --- a/tests/baselines/reference/variadicTuples1.js +++ b/tests/baselines/reference/variadicTuples1.js @@ -361,6 +361,19 @@ interface Desc { declare const a: Desc<[string, number, boolean], object>; const b = a.bind("", 1); // Desc<[boolean], object> + +// Repro from #39607 + +declare function getUser(id: string, options?: { x?: string }): string; + +declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void; + +function callApi(method: (...args: [...T, object]) => U) { + return (...args: [...T]) => method(...args, {}); +} + +callApi(getUser); +callApi(getOrgUser); //// [variadicTuples1.js] @@ -568,6 +581,17 @@ function f23(args) { var v3 = f22(["foo", 42]); // [string] } var b = a.bind("", 1); // Desc<[boolean], object> +function callApi(method) { + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return method.apply(void 0, __spreadArrays(args, [{}])); + }; +} +callApi(getUser); +callApi(getOrgUser); //// [variadicTuples1.d.ts] @@ -720,3 +744,11 @@ interface Desc { } declare const a: Desc<[string, number, boolean], object>; declare const b: Desc<[boolean], object>; +declare function getUser(id: string, options?: { + x?: string; +}): string; +declare function getOrgUser(id: string, orgId: number, options?: { + y?: number; + z?: boolean; +}): void; +declare function callApi(method: (...args: [...T, object]) => U): (...args_0: T) => U; diff --git a/tests/baselines/reference/variadicTuples1.symbols b/tests/baselines/reference/variadicTuples1.symbols index e7c9db73fc13f..c8dce6f67e6a7 100644 --- a/tests/baselines/reference/variadicTuples1.symbols +++ b/tests/baselines/reference/variadicTuples1.symbols @@ -1244,3 +1244,43 @@ const b = a.bind("", 1); // Desc<[boolean], object> >a : Symbol(a, Decl(variadicTuples1.ts, 360, 13)) >bind : Symbol(Desc.bind, Decl(variadicTuples1.ts, 356, 34)) +// Repro from #39607 + +declare function getUser(id: string, options?: { x?: string }): string; +>getUser : Symbol(getUser, Decl(variadicTuples1.ts, 361, 24)) +>id : Symbol(id, Decl(variadicTuples1.ts, 365, 25)) +>options : Symbol(options, Decl(variadicTuples1.ts, 365, 36)) +>x : Symbol(x, Decl(variadicTuples1.ts, 365, 48)) + +declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void; +>getOrgUser : Symbol(getOrgUser, Decl(variadicTuples1.ts, 365, 71)) +>id : Symbol(id, Decl(variadicTuples1.ts, 367, 28)) +>orgId : Symbol(orgId, Decl(variadicTuples1.ts, 367, 39)) +>options : Symbol(options, Decl(variadicTuples1.ts, 367, 54)) +>y : Symbol(y, Decl(variadicTuples1.ts, 367, 66)) +>z : Symbol(z, Decl(variadicTuples1.ts, 367, 78)) + +function callApi(method: (...args: [...T, object]) => U) { +>callApi : Symbol(callApi, Decl(variadicTuples1.ts, 367, 100)) +>T : Symbol(T, Decl(variadicTuples1.ts, 369, 17)) +>U : Symbol(U, Decl(variadicTuples1.ts, 369, 42)) +>method : Symbol(method, Decl(variadicTuples1.ts, 369, 53)) +>args : Symbol(args, Decl(variadicTuples1.ts, 369, 62)) +>T : Symbol(T, Decl(variadicTuples1.ts, 369, 17)) +>U : Symbol(U, Decl(variadicTuples1.ts, 369, 42)) + + return (...args: [...T]) => method(...args, {}); +>args : Symbol(args, Decl(variadicTuples1.ts, 370, 12)) +>T : Symbol(T, Decl(variadicTuples1.ts, 369, 17)) +>method : Symbol(method, Decl(variadicTuples1.ts, 369, 53)) +>args : Symbol(args, Decl(variadicTuples1.ts, 370, 12)) +} + +callApi(getUser); +>callApi : Symbol(callApi, Decl(variadicTuples1.ts, 367, 100)) +>getUser : Symbol(getUser, Decl(variadicTuples1.ts, 361, 24)) + +callApi(getOrgUser); +>callApi : Symbol(callApi, Decl(variadicTuples1.ts, 367, 100)) +>getOrgUser : Symbol(getOrgUser, Decl(variadicTuples1.ts, 365, 71)) + diff --git a/tests/baselines/reference/variadicTuples1.types b/tests/baselines/reference/variadicTuples1.types index 6882761339374..dce37b089e51c 100644 --- a/tests/baselines/reference/variadicTuples1.types +++ b/tests/baselines/reference/variadicTuples1.types @@ -1279,3 +1279,44 @@ const b = a.bind("", 1); // Desc<[boolean], object> >"" : "" >1 : 1 +// Repro from #39607 + +declare function getUser(id: string, options?: { x?: string }): string; +>getUser : (id: string, options?: { x?: string | undefined; } | undefined) => string +>id : string +>options : { x?: string | undefined; } | undefined +>x : string | undefined + +declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void; +>getOrgUser : (id: string, orgId: number, options?: { y?: number | undefined; z?: boolean | undefined; } | undefined) => void +>id : string +>orgId : number +>options : { y?: number | undefined; z?: boolean | undefined; } | undefined +>y : number | undefined +>z : boolean | undefined + +function callApi(method: (...args: [...T, object]) => U) { +>callApi : (method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U +>method : (...args_0: T, args_1: object) => U +>args : [...T, object] + + return (...args: [...T]) => method(...args, {}); +>(...args: [...T]) => method(...args, {}) : (...args_0: T) => U +>args : [...T] +>method(...args, {}) : U +>method : (...args_0: T, args_1: object) => U +>...args : T[number] +>args : [...T] +>{} : {} +} + +callApi(getUser); +>callApi(getUser) : (id: string) => string +>callApi : (method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U +>getUser : (id: string, options?: { x?: string | undefined; } | undefined) => string + +callApi(getOrgUser); +>callApi(getOrgUser) : (id: string, orgId: number) => void +>callApi : (method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U +>getOrgUser : (id: string, orgId: number, options?: { y?: number | undefined; z?: boolean | undefined; } | undefined) => void + diff --git a/tests/cases/conformance/types/tuple/variadicTuples1.ts b/tests/cases/conformance/types/tuple/variadicTuples1.ts index e6562f20ccc4c..2a34d06e2b0e1 100644 --- a/tests/cases/conformance/types/tuple/variadicTuples1.ts +++ b/tests/cases/conformance/types/tuple/variadicTuples1.ts @@ -363,3 +363,16 @@ interface Desc { declare const a: Desc<[string, number, boolean], object>; const b = a.bind("", 1); // Desc<[boolean], object> + +// Repro from #39607 + +declare function getUser(id: string, options?: { x?: string }): string; + +declare function getOrgUser(id: string, orgId: number, options?: { y?: number, z?: boolean }): void; + +function callApi(method: (...args: [...T, object]) => U) { + return (...args: [...T]) => method(...args, {}); +} + +callApi(getUser); +callApi(getOrgUser);