🤖 Merge PR #46971 [lodash] Update return types for debounce & throttle by @dobesv

- 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
This commit is contained in:
Dobes Vandermeer 2020-08-28 18:31:26 -07:00 committed by GitHub
parent 41d3df53a0
commit 93d8f9d710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 43 deletions

View File

@ -254,10 +254,6 @@ declare module "../index" {
type AnyKindOfDictionary =
| Dictionary<unknown>
| NumericDictionary<unknown>;
interface Cancelable {
cancel(): void;
flush(): void;
}
type PartialShallow<T> = {
[P in keyof T]?: T[P] extends object ? object : T[P]
};

View File

@ -368,6 +368,32 @@ declare module "../index" {
*/
trailing?: boolean;
}
interface DebouncedFunc<T extends (...args: any[]) => 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<T>): ReturnType<T> | 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<T> | 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<T extends (...args: any) => any>(func: T, wait?: number, options?: DebounceSettings): T & Cancelable;
debounce<T extends (...args: any) => any>(func: T, wait?: number, options?: DebounceSettings): DebouncedFunc<T>;
}
interface Function<T extends (...args: any) => any> {
/**
* @see _.debounce
*/
debounce(wait?: number, options?: DebounceSettings): Function<T & Cancelable>;
debounce(
wait?: number,
options?: DebounceSettings
): T extends (...args: any[]) => any ? Function<DebouncedFunc<T>> : never;
}
interface FunctionChain<T extends (...args: any) => any> {
/**
* @see _.debounce
*/
debounce(wait?: number, options?: DebounceSettings): FunctionChain<T & Cancelable>;
debounce(
wait?: number,
options?: DebounceSettings
): T extends (...args: any[]) => any ? FunctionChain<DebouncedFunc<T>> : 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<T extends (...args: any) => any>(func: T, wait?: number, options?: ThrottleSettings): T & Cancelable;
throttle<T extends (...args: any) => any>(func: T, wait?: number, options?: ThrottleSettings): DebouncedFunc<T>;
}
interface Function<T extends (...args: any) => any> {
/**
* @see _.throttle
*/
throttle(wait?: number, options?: ThrottleSettings): Function<T & Cancelable>;
throttle(
wait?: number,
options?: ThrottleSettings
): T extends (...args: any[]) => any ? Function<DebouncedFunc<T>> : never;
}
interface FunctionChain<T extends (...args: any) => any> {
/**
* @see _.throttle
*/
throttle(wait?: number, options?: ThrottleSettings): FunctionChain<T & Cancelable>;
throttle(
wait?: number,
options?: ThrottleSettings
): T extends (...args: any[]) => any ? FunctionChain<DebouncedFunc<T>> : never;
}
interface LoDashStatic {
/**

26
types/lodash/fp.d.ts vendored
View File

@ -20,7 +20,7 @@ declare namespace _ {
(func: lodash.__, n: number): LodashAfter1x2;
<TFunc extends (...args: any[]) => any>(func: TFunc, n: number): TFunc;
}
type LodashAfter1x1<TFunc> = (n: number) => TFunc;
type LodashAfter1x1<TFunc extends (...args: any[]) => any> = (n: number) => TFunc;
type LodashAfter1x2 = <TFunc extends (...args: any[]) => any>(func: TFunc) => TFunc;
interface LodashEvery {
<T>(predicate: lodash.ValueIterateeCustom<T, boolean>): LodashEvery1x1<T>;
@ -214,7 +214,7 @@ declare namespace _ {
(func: lodash.__, n: number): LodashBefore1x2;
<TFunc extends (...args: any[]) => any>(func: TFunc, n: number): TFunc;
}
type LodashBefore1x1<TFunc> = (n: number) => TFunc;
type LodashBefore1x1<TFunc extends (...args: any[]) => any> = (n: number) => TFunc;
type LodashBefore1x2 = <TFunc extends (...args: any[]) => any>(func: TFunc) => TFunc;
interface LodashBind {
(func: (...args: any[]) => any): LodashBind1x1;
@ -424,10 +424,10 @@ declare namespace _ {
interface LodashDebounce {
(wait: number): LodashDebounce1x1;
<T extends (...args: any) => any>(wait: lodash.__, func: T): LodashDebounce1x2<T>;
<T extends (...args: any) => any>(wait: number, func: T): T & lodash.Cancelable;
<T extends (...args: any) => any>(wait: number, func: T): lodash.DebouncedFunc<T>;
}
type LodashDebounce1x1 = <T extends (...args: any) => any>(func: T) => T & lodash.Cancelable;
type LodashDebounce1x2<T> = (wait: number) => T & lodash.Cancelable;
type LodashDebounce1x1 = <T extends (...args: any) => any>(func: T) => lodash.DebouncedFunc<T>;
type LodashDebounce1x2<T extends (...args: any) => any> = (wait: number) => lodash.DebouncedFunc<T>;
type LodashDeburr = (string: string) => string;
interface LodashDefaults {
<TSource>(source: TSource): LodashDefaults1x1<TSource>;
@ -1739,12 +1739,12 @@ declare namespace _ {
type LodashInRange1x5 = (end: number) => boolean;
type LodashInRange1x6 = (start: number) => boolean;
interface LodashIntersection {
<T>(arrays2: lodash.List<T>): LodashIntersection1x1<T>;
<T>(arrays2: lodash.__, arrays: lodash.List<T>): LodashIntersection1x2<T>;
<T>(arrays2: lodash.List<T>, arrays: lodash.List<T>): T[];
<T>(arrays2: lodash.List<T> | null | undefined): LodashIntersection1x1<T>;
<T>(arrays2: lodash.__, arrays: lodash.List<T> | null | undefined): LodashIntersection1x2<T>;
<T>(arrays2: lodash.List<T> | null | undefined, arrays: lodash.List<T> | null | undefined): T[];
}
type LodashIntersection1x1<T> = (arrays: lodash.List<T>) => T[];
type LodashIntersection1x2<T> = (arrays2: lodash.List<T>) => T[];
type LodashIntersection1x1<T> = (arrays: lodash.List<T> | null | undefined) => T[];
type LodashIntersection1x2<T> = (arrays2: lodash.List<T> | null | undefined) => T[];
interface LodashIntersectionBy {
<T1, T2>(iteratee: lodash.ValueIteratee<T1 | T2>): LodashIntersectionBy1x1<T1, T2>;
<T1>(iteratee: lodash.__, array: lodash.List<T1> | null): LodashIntersectionBy1x2<T1>;
@ -4161,10 +4161,10 @@ declare namespace _ {
interface LodashThrottle {
(wait: number): LodashThrottle1x1;
<T extends (...args: any) => any>(wait: lodash.__, func: T): LodashThrottle1x2<T>;
<T extends (...args: any) => any>(wait: number, func: T): T & lodash.Cancelable;
<T extends (...args: any) => any>(wait: number, func: T): lodash.DebouncedFunc<T>;
}
type LodashThrottle1x1 = <T extends (...args: any) => any>(func: T) => T & lodash.Cancelable;
type LodashThrottle1x2<T> = (wait: number) => T & lodash.Cancelable;
type LodashThrottle1x1 = <T extends (...args: any) => any>(func: T) => lodash.DebouncedFunc<T>;
type LodashThrottle1x2<T extends (...args: any) => any> = (wait: number) => lodash.DebouncedFunc<T>;
interface LodashThru {
<T, TResult>(interceptor: (value: T) => TResult): LodashThru1x1<T, TResult>;
<T>(interceptor: lodash.__, value: T): LodashThru1x2<T>;

View File

@ -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<DebouncedFunc<(n: number, s: string) => boolean>>
_.chain(func).debounce(42, options); // $ExpectType FunctionChain<DebouncedFunc<(n: number, s: string) => 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<DebouncedFunc<(a: number, b: string) => boolean>>
_(func).throttle(42); // $ExpectType Function<DebouncedFunc<(a: number, b: string) => boolean>>
_(func).throttle(42, options); // $ExpectType Function<DebouncedFunc<(a: number, b: string) => boolean>>
_.chain(func).throttle(); // $ExpectType FunctionChain<DebouncedFunc<(a: number, b: string) => boolean>>
_.chain(func).throttle(42); // $ExpectType FunctionChain<DebouncedFunc<(a: number, b: string) => boolean>>
_.chain(func).throttle(42, options); // $ExpectType FunctionChain<DebouncedFunc<(a: number, b: string) => 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

View File

@ -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;