打字稿中的安全类型去抖函数

jun*_*ray 5 types debouncing typescript

我在打字稿中有以下去抖功能:

export function debounce<T>(
  callback: (...args: any[]) => void,
  wait: number,
  context?: T,
  immediate?: boolean
) {
  let timeout: ReturnType<typeof setTimeout> | null;

  return (...args: any[]) => {
    const later = () => {
      timeout = null;

      if (!immediate) {
        callback.apply(context, args);
      }
    };
    const callNow = immediate && !timeout;

    if (typeof timeout === "number") {
      clearTimeout(timeout);
    }

    timeout = setTimeout(later, wait);

    if (callNow) {
      callback.apply(context, args);
    }
  };
}

Run Code Online (Sandbox Code Playgroud)

我正在寻找一种更好的方法来 ...args: any[] 使用更安全的类型进行转换。

我怎样才能改变它?

更新

我想出了这个解决方案:

export function debounce<T = unknown, R = void>(
  callback: (...args: unknown[]) => R,
  wait: number,
  context?: T,
  immediate?: boolean
) {
Run Code Online (Sandbox Code Playgroud)

你怎么认为?

Jar*_*ith 6

我做了一些改变。

首先,我们希望泛型类型是一个函数,以便稍后我们可以安全地获取Paramters实用程序类型的参数。其次,我个人喜欢首先等待时间,因为我经常对许多具有部分应用的侦听器应用相同的去抖计时,YMMV。第三,我们希望返回一个带有类型this参数的常规(非箭头)函数,以便调用者不需要显式传递上下文。

function debounce<T extends (...args: any[]) => void>(
  wait: number,
  callback: T,
  immediate = false,
)  {
  // This is a number in the browser and an object in Node.js,
  // so we'll use the ReturnType utility to cover both cases.
  let timeout: ReturnType<typeof setTimeout> | null;

  return function <U>(this: U, ...args: Parameters<typeof callback>) {
    const context = this;
    const later = () => {
      timeout = null;

      if (!immediate) {
        callback.apply(context, args);
      }
    };
    const callNow = immediate && !timeout;

    if (typeof timeout === "number") {
      clearTimeout(timeout);
    }

    timeout = setTimeout(later, wait);

    if (callNow) {
      callback.apply(context, args);
    }
  };
}
Run Code Online (Sandbox Code Playgroud)

对于用法,我们可以使用普通函数和方法:

const handler: (evt: Event) => void = debounce(500, (evt: Event) => console.log(evt.target));
class Foo {
    constructor () {
        // can also type-safely decorate methods
        this.bar = debounce(500, this.bar.bind(this));
    }

    bar (evt: Event): void {
        console.log(evt.target);
    }
}
Run Code Online (Sandbox Code Playgroud)

即使在对象文字的方法上:

interface Bar {
    a: number,
    f: () => void
}

const bar: Bar = {
    a: 1,
    f: debounce<(this: Bar) => void>(100, function() { console.log(this.a); }),
}
Run Code Online (Sandbox Code Playgroud)

操场