項目12 可能なら関数式全体に型を適用する
関数式を使う利点
TypeScriptで関数式を使う利点は、パラメータや戻り値の型を個別に指定する代わりに、関数全体に対して一度に型宣言を適用できる点
code:ts
type BinaryFn = (a: number, b: number) => number;
const add: BinaryFn = (a, b) => a + b;
const sub: BinaryFn = (a, b) => a - b;
const mul: BinaryFn = (a, b) => a * b;
const div: BinaryFn = (a, b) => a / b;
こうすることで、型定義と実装が切り分けられ、ロジックが明確になる
関数シグネチャの型
ライブラリは、よく関数シグネチャを型として提供している
React
MouseEventHandler型が用意されており、関数のパラメータ型としてMouseEvent 型を使用する必要がない
ライブラリの作者はよく使うコールバックの型宣言を提供するようにする
他の関数シグネチャと一致させたい場合
fetch関数を拡張して使う場合
fetch関数の型定義
code:ts
declare function fetch(
input: RequestInfo, init?: RequestInit,
): Promise<Response>;
fetch関数は、リクエストエラー発生時のハンドリングができないため、ステータスチェックを行う必要がある
code:ts
async function checkedFetch(input: RequestInfo, init?: RequestInit) {
const response = await fetch(input, init);
if (!response.ok) {
// async関数で例外を投げると拒否されたPromiseになる
throw new Error(Request failed: ${response.status});
}
return response;
}
上記の関数文ではなく、関数式に置き換えて関数全体に型(型アノテーションにtypeof fetchを指定)を適応できるようにする
code:ts
const checkedFetch: typeof fetch = async (input, init) => {
const response = await fetch(input, init);
if (!response.ok) {
throw new Error(Request failed: ${response.status});
}
return response;
}
パラメータの型は他の関数の型と一致させ、戻り値の型は変更させたい場合
レストパラメータとParametersユーティリティ型を使う
code:ts
async function fetchANumber(
...args: Parameters<typeof fetch>
): Promise<number> {
const response = await checkedFetch(...args);
const num = Number(await response.text());
if (isNaN(num)) {
throw new Error(Response was not a number.);
}
return num;
}