TL;DR

  • 型推論が効く場所では、型アノテーションは不要である。
  • 理想は、関数のシグネチャには型アノテーションがあり、関数本体のローカル変数にはない状態である。
  • ただし、オブジェクトリテラルと一部の戻り値の型には、推論できる場合でも型アノテーションを付ける。

内容

シグネチャにだけ型を書く

関数やメソッドのシグネチャには型アノテーションを書き、本体のローカル変数には書かないのが理想である。ローカル変数の型は、引数の型から推論される。

function logProduct(product: Product) {
  const { id, name, price } = product
  console.log(id, name, price)
}

シグネチャであっても、引数にデフォルト値がある場合や、関数をコールバックとして渡す場合は、型アノテーションが要らない。

function parseNumber(str: string, base = 10) { ... }
// Express.js
app.get("/health", (req, res) => {
  res.json({ message: "Hello, world" })
})

推論できても型アノテーションを付けるケース

1 つ目はオブジェクトリテラルである。型アノテーションを付けると余剰プロパティチェックが有効になる。

2 つ目は戻り値の型である。ただし付けるべきなのは、return が複数ある場合、公開 API の一部である場合、名前付きの型を返したい場合に限られる。戻り値の型を書くと、次の利点がある。

  • 最初に完全な型を書くことで、本当に必要な関数を実装できる(TDD に近い考え方)。
  • TypeScript が戻り値の型を解析する手間を省ける(項目78)。
  • 名前付きの型を返せる。

たとえば次の add の戻り値は、{ x: number; y: number; } と推論される。

interface Vector2D {
  x: number
  y: number
}
 
function add(a: Vector2D, b: Vector2D) {
  return { x: a.x + b.x, y: a.y + b.y }
}

これを Vector2D として扱いたい場合は、function add(a: Vector2D, b: Vector2D): Vector2D と戻り値の型を明示する。

キーワード