TL;DR

  • 安全でない型アサーションや any は、関数の内部に隠したほうが使いやすい関数になる。
  • 実装の型エラーを消すために、関数の型シグネチャを妥協してはいけない。

内容

型アサーションを関数の内部に隠す

次の checkedFetchJSON は unknown を返す。

async function checkedFetchJSON(url: string): Promise<unknown> {
  const response = await fetch(url)
  if (!response.ok) {
    throw new Error(`Unable to fetch! ${response.statusText}`)
  }
  return response.json()
}

これをそのまま返すと、利用者が毎回型アサーションを書かなければならない。関数の内部でアサーションし、具体的な型を返すほうが扱いやすい。

// 🙅 NG: unknown だと利用者は型アサーションを必ずする必要があるので使いづらい
const fetchPeak = async (peakId: string): Promise<unknown> =>
  checkedFetchJSON(`/api/mountain-peaks/${peakId}`)
 
// 🙆 OK: MountainPeak という具体的な型なので扱いやすい
const fetchPeak = async (peakId: string): Promise<MountainPeak> =>
  checkedFetchJSON(`/api/mountain-peaks/${peakId}`) as Promise<MountainPeak>

このとき、関数の内部でデータを検証するとより安全になる。

const fetchPeak = async (peakId: string): Promise<MountainPeak> => {
  const maybePeak = checkedFetchJSON(`/api/mountain-peaks/${peakId}`)
  if (!maybePeak || typeof maybePeak !== "object" || !("firstAccentYear" in maybePeak)) {
    throw new Error(`Invalid mountain peak: ${JSON.stringify(maybePeak)}`)
  }
  // ...
}

型シグネチャを妥協しない

実装の型エラーを直すために、パラメータを any にするなどして型シグネチャを妥協してはいけない。次の例では、b を any にしたせいで、実行時にクラッシュする呼び出しが通ってしまう。

// 🙅 NG: 実行時にクラッシュするコードが許される
const shallowObjectEqual = (a: object, b: any): boolean => {
  for (const [k, aVal] of Object.entries(a)) {
    if (!(k in b) || aVal !== b[k]) {
      return false
    }
  }
  return Object.keys(a).length === Object.keys(b).length
}
 
shallowObjectEqual({ a: 1 }, null) // 実行時エラー

シグネチャは object のままにし、any は必要な式だけに使う(項目43 可能なかぎり狭いスコープでany型を使う)。

// 🙆 OK: any も最低限のスコープ内に収まっている
const shallowObjectEqual = (a: object, b: object): boolean => {
  for (const [k, aVal] of Object.entries(a)) {
    // `k in b` をチェックしているので、`(b as any)[k]` は安全
    if (!(k in b) || aVal !== (b as any)[k]) {
      return false
    }
  }
  return Object.keys(a).length === Object.keys(b).length
}
 
shallowObjectEqual({ a: 1 }, null) // 型エラー

型アサーションを使うときの注意

型アサーションを使うときは、必ずコメントで理由を説明し、単体テストも重点的に書く(項目9 型アノテーションを型アサーションより優先的に使用する)。

キーワード