コールバックに対するTypeScriptの型チェック
私は最近TypeScriptの学習を始めたばかりですが、概念的に理解できないこの問題にぶつかりました。この関数のパラメーターの型を定義することは間違っていますか?
setTimeout((a: string) => {
console.log(a); // ==> Prints 5 as a number
}, 1, 5);
コールバックを呼び出すときになぜ型チェックが行われないのですか?
TypeScript にエラーを出させるにはどうすればいいですか?
このようなことに直面したとき、一般的に私の解決策は何ですか?
回答 #1
これは TypeScript の既知のバグです。microsoft/TypeScript#32186 を参照してください。setTimeout() の型定義は次のようになっています
setTimeout(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
どんな引数のリストでも受け入れ、型を気にしません。そして TimerHandler は単に次のように定義されています
type TimerHandler = string | Function
これは安全でない型指定されていない Function 型を使用します。そのため、setTimeout() は残念ながら TypeScript では非常に緩い型指定になっています。このような状況では、宣言のマージを使用してより良い呼び出しシグネチャを追加することがよくありますが、この場合、コンパイラーが安全でない呼び出しシグネチャに戻るのを止めるものは何もありません。
これは単にTSの制限のようです。この問題は「バックログ」に記載されているので、すぐに対応される予定はありません。microsoft/TypeScript#32186 に行って👍を押して、修正を支持することはできますが、大きく変わる可能性は低いです。
今のところ、回避策しかありません。
あなたは自分のローカルコピーのlib.dom.tsライブラリを使って、safeTimeout()の定義を変更することを決めることもできますが、それを維持するのは非常に面倒です。
使用できる回避策は、setTimeout をより型が強く指定された独自の関数でラップし、それを使用することだけです。おそらく次のようなものです:
const safeSetTimeout: <A extends any[]>(
handler: (...args: A) => void, timeout?: number, ...args: A
) => number = setTimeout;
これはジェネリクスを使用して、handler コールバックが受け取る args を、setTimeout() 自体に渡される args と同じ型に強く型付けします。動作を見てみましょう:
safeSetTimeout((a: string) => {
console.log(a);
}, 1, 5); // <-- error! number is not assignable to string
// ~
素晴らしいことに、5 に対して期待されたコンパイルエラーが表示され、これは number ではなく string であるべきだと言われます。残念ながら、今のところこれが限界です。
コードへのプレイグラウンドリンク
