angus-c / just

A library of dependency-free JavaScript utilities that do just one thing.
https://anguscroll.com/just
MIT License
6.06k stars 209 forks source link

just-debounce-it, types and async functions #574

Closed achingbrain closed 10 months ago

achingbrain commented 10 months ago

I have an async function I'd like to debounce while using the wait parameter:

import debounce from 'just-debounce-it'

async function myFunction (): Promise<void> => {
  // do some async work
}

const debounced = debounce(myFunction, 10)

This causes TypeScript to become deeply upset:

Type '(() => void) & MethodTypes' is not assignable to type '() => Promise<void>'.
  Type 'void' is not assignable to type 'Promise<void>'.

The types for this function are:

declare function debounce<T extends Function>(
  fn: T,
  wait?: 0,
  callFirst?: boolean
): T & MethodTypes;

declare function debounce<T extends Function>(
  fn: T,
  wait: number,
  callFirst: true
): T & MethodTypes;

declare function debounce<T extends Function>(
  fn: T,
  wait: number,
  callFirst?: false
): ((...args: ArgumentTypes<T>) => void) & MethodTypes;

Because I pass a function and a number, the third signature is selected which wants the return type of the passed function to be void, which it isn't, it's Promise<void>.

To fix this, the third signature could be changed to either:

declare function debounce<T extends Function>(
  fn: T,
  wait: number,
  callFirst?: false
): T & MethodTypes;

or:

declare function debounce<T extends Function>(
  fn: T,
  wait: number,
  callFirst?: false
): ((...args: ArgumentTypes<T>) => ReturnType<T>) & MethodTypes;

Though I'm not sure why ((...args: ArgumentTypes<T>) => void) & MethodTypes was used instead of T & MethodTypes in the first place?

achingbrain commented 10 months ago

Actually it looks like passing a promise-returning function to just-debounce-it can result in unhandled promise rejections since the function is invoked here and there's no way to await or .catch on the return value:

https://github.com/angus-c/just/blob/d8c5dd18941062d8db7e9310ecc8f53fd607df54/packages/function-debounce/index.mjs#L36

I think it's better to just use p-debounce instead of just-debounce-it.