1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

debounceのTypescriptコード

Posted at

以下の記事のdebounce関数を使用したいと思ったのですが、使用する環境はTypescriptなもんでそのままコピできません。コピペで仕事ができない辛い時代になってきました。

なので調整してみました。

完成品はこちら

function debounce<T, F extends (...args: any[]) => void>(
  thisArg: T,
  func: F,
  timeout = 300
): (...args: Parameters<F>) => void {
  let timer: ReturnType<typeof setTimeout>;
  return (...args: Parameters<F>): void => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(thisArg, args);
    }, timeout);
  };
}

function saveInput(): void {
  console.log('Saving data');
}

const processChange: (...args: any[]) => void = debounce(undefined, () => saveInput());

Q. どうやって解決したの?

A. ChatGPT です。
といってもそのまま「Tyepscriptに変換して!」ってお願いしても、一発でエラーのないコードは生成されないもんです。
最初にいただいたコードはこちら。

function debounce<F extends (...args: any[]) => void>(func: F, timeout = 300): (...args: Parameters<F>) => void {
  let timer: number | undefined;
  return (...args: Parameters<F>): void => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, timeout);
  };
}

function saveInput(): void {
  console.log('Saving data');
}

const processChange: (...args: any[]) => void = debounce(() => saveInput());

このままだとtypescriptエラーが発生します。

setTimeout の返り値の型

まず timer = setTimeout(() => { の行で、
Type 'Timeout' is not assignable to type 'number'.ts(2322)
というエラーが発生。調べてみると、環境によって number だったり NodeJS.Timeout だったりするので、Typescriptに型推論させたほうが良いとのこと。
なので

- let timer: number | undefined;
+ let timer: ReturnType<typeof setTimeout>;

とする。

this の型

次に func.apply(this, args); の行で
'this' implicitly has type 'any' because it does not have a type annotation.ts(2683)
というエラーが発生しました。

this を undefined にしたり

- func.apply(this, args);
+ func.apply(undefined, args);

this の型を 明示的に any にしたり

- return (...args: Parameters<F>): void => {
+ return function (this: any, ...args: Parameters<F>): void {

のようにしてもいいかなーと思ったのですが、せっかく apply メソッドを使っているのでちゃんと活用したいところ。

ChatGPTさんが、ジェネリクスを使いなさいと、コードまでくださったので、その通りにします。

- function debounce<F extends (...args: any[]) => void>(
-   func: F,
-   timeout = 300
- ): (...args: Parameters<F>) => void {
...
-     func.apply(this, args);
...
- const processChange: (...args: any[]) => void = debounce(() => saveInput());


+ function debounce<T, F extends (...args: any[]) => void>(
+   thisArg: T,
+   func: F,
+   timeout = 300
+ ): (...args: Parameters<F>) => void {
...
+     func.apply(thisArg, args);
...
+ const processChange: (...args: any[]) => void = debounce(undefined, () => saveInput());

呼び出す側で thisArg を指定する必要がありますが、オブジェクトのメソッドでも使用したいのでこのようにする。

おまけ

<button onclick="processChange()">Click me</button> のように、onclickハンドラ内で直接processChangeを呼び出すときは、以下のようにしてグローバル変数に登録をする。
あまりこういうことしたことがないので、備忘録。

(window as any).processChange = debounce(window, () => saveInput());

参考記事

setTimeoutの型注釈がnumber型ではエラーになる理由 #React - Qiita
this - JavaScript | MDNMDN Web DocsMDN logoMozilla logo

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?