From 93d8f9d7102925e1a39852627465a44a0ff670cf Mon Sep 17 00:00:00 2001 From: Dobes Vandermeer Date: Fri, 28 Aug 2020 18:31:26 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#46971=20[lodash]?= =?UTF-8?q?=20Update=20return=20types=20for=20debounce=20&=20throttle=20by?= =?UTF-8?q?=20@dobesv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - functions returned by `throttle` & `debounce` can return `undefined` if the function invokation is delayed - the `flush()` method returns the return value of the last invokation, if available --- types/lodash/common/common.d.ts | 4 --- types/lodash/common/function.d.ts | 50 +++++++++++++++++++++++++---- types/lodash/fp.d.ts | 26 +++++++-------- types/lodash/lodash-tests.ts | 38 +++++++++++----------- types/lodash/scripts/generate-fp.ts | 7 +++- 5 files changed, 82 insertions(+), 43 deletions(-) diff --git a/types/lodash/common/common.d.ts b/types/lodash/common/common.d.ts index 93a792118d..b9e6f17708 100644 --- a/types/lodash/common/common.d.ts +++ b/types/lodash/common/common.d.ts @@ -254,10 +254,6 @@ declare module "../index" { type AnyKindOfDictionary = | Dictionary | NumericDictionary; - interface Cancelable { - cancel(): void; - flush(): void; - } type PartialShallow = { [P in keyof T]?: T[P] extends object ? object : T[P] }; diff --git a/types/lodash/common/function.d.ts b/types/lodash/common/function.d.ts index 5ef882c213..721452ae0d 100644 --- a/types/lodash/common/function.d.ts +++ b/types/lodash/common/function.d.ts @@ -368,6 +368,32 @@ declare module "../index" { */ trailing?: boolean; } + interface DebouncedFunc any> { + /** + * Call the original function, but applying the debounce rules. + * + * If the debounced function can be run immediately, this calls it and returns its return + * value. + * + * Otherwise, it returns the return value of the last invokation, or undefined if the debounced + * function was not invoked yet. + */ + (...args: Parameters): ReturnType | undefined; + + /** + * Throw away any pending invokation of the debounced function. + */ + cancel(): void; + + /** + * If there is a pending invokation of the debounced function, invoke it immediately and return + * its return value. + * + * Otherwise, return the value from the last invokation, or undefined if the debounced function + * was never invoked. + */ + flush(): ReturnType | undefined; + } interface LoDashStatic { /** * Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since @@ -389,19 +415,25 @@ declare module "../index" { * @param options.trailing Specify invoking on the trailing edge of the timeout. * @return Returns the new debounced function. */ - debounce any>(func: T, wait?: number, options?: DebounceSettings): T & Cancelable; + debounce any>(func: T, wait?: number, options?: DebounceSettings): DebouncedFunc; } interface Function any> { /** * @see _.debounce */ - debounce(wait?: number, options?: DebounceSettings): Function; + debounce( + wait?: number, + options?: DebounceSettings + ): T extends (...args: any[]) => any ? Function> : never; } interface FunctionChain any> { /** * @see _.debounce */ - debounce(wait?: number, options?: DebounceSettings): FunctionChain; + debounce( + wait?: number, + options?: DebounceSettings + ): T extends (...args: any[]) => any ? FunctionChain> : never; } interface LoDashStatic { /** @@ -1324,19 +1356,25 @@ declare module "../index" { * @param options.trailing Specify invoking on the trailing edge of the timeout. * @return Returns the new throttled function. */ - throttle any>(func: T, wait?: number, options?: ThrottleSettings): T & Cancelable; + throttle any>(func: T, wait?: number, options?: ThrottleSettings): DebouncedFunc; } interface Function any> { /** * @see _.throttle */ - throttle(wait?: number, options?: ThrottleSettings): Function; + throttle( + wait?: number, + options?: ThrottleSettings + ): T extends (...args: any[]) => any ? Function> : never; } interface FunctionChain any> { /** * @see _.throttle */ - throttle(wait?: number, options?: ThrottleSettings): FunctionChain; + throttle( + wait?: number, + options?: ThrottleSettings + ): T extends (...args: any[]) => any ? FunctionChain> : never; } interface LoDashStatic { /** diff --git a/types/lodash/fp.d.ts b/types/lodash/fp.d.ts index faaba37608..be3526af02 100644 --- a/types/lodash/fp.d.ts +++ b/types/lodash/fp.d.ts @@ -20,7 +20,7 @@ declare namespace _ { (func: lodash.__, n: number): LodashAfter1x2; any>(func: TFunc, n: number): TFunc; } - type LodashAfter1x1 = (n: number) => TFunc; + type LodashAfter1x1 any> = (n: number) => TFunc; type LodashAfter1x2 = any>(func: TFunc) => TFunc; interface LodashEvery { (predicate: lodash.ValueIterateeCustom): LodashEvery1x1; @@ -214,7 +214,7 @@ declare namespace _ { (func: lodash.__, n: number): LodashBefore1x2; any>(func: TFunc, n: number): TFunc; } - type LodashBefore1x1 = (n: number) => TFunc; + type LodashBefore1x1 any> = (n: number) => TFunc; type LodashBefore1x2 = any>(func: TFunc) => TFunc; interface LodashBind { (func: (...args: any[]) => any): LodashBind1x1; @@ -424,10 +424,10 @@ declare namespace _ { interface LodashDebounce { (wait: number): LodashDebounce1x1; any>(wait: lodash.__, func: T): LodashDebounce1x2; - any>(wait: number, func: T): T & lodash.Cancelable; + any>(wait: number, func: T): lodash.DebouncedFunc; } - type LodashDebounce1x1 = any>(func: T) => T & lodash.Cancelable; - type LodashDebounce1x2 = (wait: number) => T & lodash.Cancelable; + type LodashDebounce1x1 = any>(func: T) => lodash.DebouncedFunc; + type LodashDebounce1x2 any> = (wait: number) => lodash.DebouncedFunc; type LodashDeburr = (string: string) => string; interface LodashDefaults { (source: TSource): LodashDefaults1x1; @@ -1739,12 +1739,12 @@ declare namespace _ { type LodashInRange1x5 = (end: number) => boolean; type LodashInRange1x6 = (start: number) => boolean; interface LodashIntersection { - (arrays2: lodash.List): LodashIntersection1x1; - (arrays2: lodash.__, arrays: lodash.List): LodashIntersection1x2; - (arrays2: lodash.List, arrays: lodash.List): T[]; + (arrays2: lodash.List | null | undefined): LodashIntersection1x1; + (arrays2: lodash.__, arrays: lodash.List | null | undefined): LodashIntersection1x2; + (arrays2: lodash.List | null | undefined, arrays: lodash.List | null | undefined): T[]; } - type LodashIntersection1x1 = (arrays: lodash.List) => T[]; - type LodashIntersection1x2 = (arrays2: lodash.List) => T[]; + type LodashIntersection1x1 = (arrays: lodash.List | null | undefined) => T[]; + type LodashIntersection1x2 = (arrays2: lodash.List | null | undefined) => T[]; interface LodashIntersectionBy { (iteratee: lodash.ValueIteratee): LodashIntersectionBy1x1; (iteratee: lodash.__, array: lodash.List | null): LodashIntersectionBy1x2; @@ -4161,10 +4161,10 @@ declare namespace _ { interface LodashThrottle { (wait: number): LodashThrottle1x1; any>(wait: lodash.__, func: T): LodashThrottle1x2; - any>(wait: number, func: T): T & lodash.Cancelable; + any>(wait: number, func: T): lodash.DebouncedFunc; } - type LodashThrottle1x1 = any>(func: T) => T & lodash.Cancelable; - type LodashThrottle1x2 = (wait: number) => T & lodash.Cancelable; + type LodashThrottle1x1 = any>(func: T) => lodash.DebouncedFunc; + type LodashThrottle1x2 any> = (wait: number) => lodash.DebouncedFunc; interface LodashThru { (interceptor: (value: T) => TResult): LodashThru1x1; (interceptor: lodash.__, value: T): LodashThru1x2; diff --git a/types/lodash/lodash-tests.ts b/types/lodash/lodash-tests.ts index 6bd2781ca5..b7efa4493c 100644 --- a/types/lodash/lodash-tests.ts +++ b/types/lodash/lodash-tests.ts @@ -3389,16 +3389,16 @@ fp.now(); // $ExpectType number trailing: false, }; - const result = _.debounce(func); // $ExpectType ((n: number, s: string) => boolean) & Cancelable + const result = _.debounce(func); // $ExpectType DebouncedFunc<(n: number, s: string) => boolean> result.cancel(); // $ExpectType void - result.flush(); // $ExpectType void - _.debounce(func, 42); // $ExpectType ((n: number, s: string) => boolean) & Cancelable - _.debounce(func, 42, options); // $ExpectType ((n: number, s: string) => boolean) & Cancelable + result.flush(); // $ExpectType boolean | undefined + _.debounce(func, 42); // $ExpectType DebouncedFunc<(n: number, s: string) => boolean> + _.debounce(func, 42, options); // $ExpectType DebouncedFunc<(n: number, s: string) => boolean> - _(func).debounce(42, options); // $ExpectType Function<((n: number, s: string) => boolean) & Cancelable> - _.chain(func).debounce(42, options); // $ExpectType FunctionChain<((n: number, s: string) => boolean) & Cancelable> - fp.debounce(42, func); // $ExpectType ((n: number, s: string) => boolean) & Cancelable - fp.debounce(42)(func); // $ExpectType ((n: number, s: string) => boolean) & Cancelable + _(func).debounce(42, options); // $ExpectType Function boolean>> + _.chain(func).debounce(42, options); // $ExpectType FunctionChain boolean>> + fp.debounce(42, func); // $ExpectType DebouncedFunc<(n: number, s: string) => boolean> + fp.debounce(42)(func); // $ExpectType DebouncedFunc<(n: number, s: string) => boolean> } // _.defer @@ -3636,18 +3636,18 @@ fp.now(); // $ExpectType number const func = (a: number, b: string): boolean => true; - _.throttle(func); // $ExpectType ((a: number, b: string) => boolean) & Cancelable - _.throttle(func, 42); // $ExpectType ((a: number, b: string) => boolean) & Cancelable - _.throttle(func, 42, options); // $ExpectType ((a: number, b: string) => boolean) & Cancelable - _(func).throttle(); // $ExpectType Function<((a: number, b: string) => boolean) & Cancelable> - _(func).throttle(42); // $ExpectType Function<((a: number, b: string) => boolean) & Cancelable> - _(func).throttle(42, options); // $ExpectType Function<((a: number, b: string) => boolean) & Cancelable> - _.chain(func).throttle(); // $ExpectType FunctionChain<((a: number, b: string) => boolean) & Cancelable> - _.chain(func).throttle(42); // $ExpectType FunctionChain<((a: number, b: string) => boolean) & Cancelable> - _.chain(func).throttle(42, options); // $ExpectType FunctionChain<((a: number, b: string) => boolean) & Cancelable> + _.throttle(func); // $ExpectType DebouncedFunc<(a: number, b: string) => boolean> + _.throttle(func, 42); // $ExpectType DebouncedFunc<(a: number, b: string) => boolean> + _.throttle(func, 42, options); // $ExpectType DebouncedFunc<(a: number, b: string) => boolean> + _(func).throttle(); // $ExpectType Function boolean>> + _(func).throttle(42); // $ExpectType Function boolean>> + _(func).throttle(42, options); // $ExpectType Function boolean>> + _.chain(func).throttle(); // $ExpectType FunctionChain boolean>> + _.chain(func).throttle(42); // $ExpectType FunctionChain boolean>> + _.chain(func).throttle(42, options); // $ExpectType FunctionChain boolean>> - fp.throttle(42, func); // $ExpectType ((a: number, b: string) => boolean) & Cancelable - fp.throttle(42)(func); // $ExpectType ((a: number, b: string) => boolean) & Cancelable + fp.throttle(42, func); // $ExpectType DebouncedFunc<(a: number, b: string) => boolean> + fp.throttle(42)(func); // $ExpectType DebouncedFunc<(a: number, b: string) => boolean> } // _.unary diff --git a/types/lodash/scripts/generate-fp.ts b/types/lodash/scripts/generate-fp.ts index ecd9c97ab4..c0f800418c 100644 --- a/types/lodash/scripts/generate-fp.ts +++ b/types/lodash/scripts/generate-fp.ts @@ -749,7 +749,12 @@ function curryParams( for (const typeParam of interfaceDef.typeParams) { // 1. retain `extends keyof X` constraints so that TObject[TKey] still works. // 2. retain `any[]` constraints so that variadic generics work. - if (!_.startsWith(typeParam.extends, "keyof ") && typeParam.extends !== "any[]") + // 3. retain `(...args: any[]) => any` constraints so that function-based generics work + if (!_.startsWith(typeParam.extends, "keyof ") + && typeParam.extends !== "any[]" + && typeParam.extends !== "(...args: any) => any" + && typeParam.extends !== "(...args: any[]) => any" + ) delete typeParam.extends; } return interfaceDef;