Skip to content

Commit

Permalink
Support variadic tuple inference from trailing optional to non-option…
Browse files Browse the repository at this point in the history
…al (#39614)

* Permit variadic tuple inference from trailing optional to non-optional

* Add tests
  • Loading branch information
ahejlsberg authored Jul 16, 2020
1 parent b6f09cc commit db79030
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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++) {
Expand Down
13 changes: 13 additions & 0 deletions tests/baselines/reference/variadicTuples1.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
return (...args: [...T]) => method(...args, {});
}

callApi(getUser);
callApi(getOrgUser);

32 changes: 32 additions & 0 deletions tests/baselines/reference/variadicTuples1.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,19 @@ interface Desc<A extends unknown[], T> {

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<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
return (...args: [...T]) => method(...args, {});
}

callApi(getUser);
callApi(getOrgUser);


//// [variadicTuples1.js]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -720,3 +744,11 @@ interface Desc<A extends unknown[], T> {
}
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<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U): (...args_0: T) => U;
40 changes: 40 additions & 0 deletions tests/baselines/reference/variadicTuples1.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends unknown[] = [], U = void>(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))

41 changes: 41 additions & 0 deletions tests/baselines/reference/variadicTuples1.types
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
>callApi : <T extends unknown[] = [], U = void>(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 : <T extends unknown[] = [], U = void>(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 : <T extends unknown[] = [], U = void>(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

13 changes: 13 additions & 0 deletions tests/cases/conformance/types/tuple/variadicTuples1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,16 @@ interface Desc<A extends unknown[], T> {

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<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U) {
return (...args: [...T]) => method(...args, {});
}

callApi(getUser);
callApi(getOrgUser);

0 comments on commit db79030

Please sign in to comment.