3秒でわかる
型注釈を書かなくてもコンパイラが値から型を割り出す仕組み。記述量を減らしながら、型チェックの恩恵はそのまま受けられます。
もう少し詳しく
どういうものか
型推論は、プログラマが型を書かなくても、代入された値や関数の中身からコンパイラが型を決める仕組みです。TypeScript で count に 3 を代入すると count は number になり、後から文字列を代入しようとするとエラーになります。関数の戻り値も同様で、return している式の型から自動で決まります。Go の短縮変数宣言、Java の var、Rust の let、C# の var も同じ考え方です。
なぜ必要か
型注釈を全部手で書くと、コードの半分が型で埋まります。特にジェネリクスが絡むと、Map
もうひとつ大きいのは、リファクタリング時に直す箇所が減ることです。関数の戻り値の形を変えたとき、注釈を書いていなければ推論が自動で追随し、実際に矛盾する場所だけがエラーになります。
具体例
const count = 3; // number と推論される
const names = ["佐藤", "鈴木"]; // string[] と推論される
function double(n: number) {
return n * 2; // 戻り値は number と推論される
}
const users = names.map((name) => ({ name, active: true }));
// users は { name: string; active: boolean }[]推論が効かないのは引数です。関数の引数は呼ばれ方が分からないため、注釈を書かないと暗黙の any になります。
似た用語との違い
型推論は静的型付けの一部です。「型を書かない = 動的型付け」と誤解されがちですが、TypeScript も Go も型を書かない箇所は推論で埋めているだけで、実行前の型検査は行われます。書かなくてよいことと、決まっていないことは別です。
つまずきやすいところ
推論の結果が思ったより広い型になることがあります。let で宣言した mode に "dark" を入れると string に推論されるため、"dark" | "light" のようなリテラル型を期待しているとうまくいきません。const で宣言するか、as const を付けると絞り込めます。
逆に狭すぎる場合もあります。空配列の 要素の型が分からない空配列は never[] になり、後から push できません。中身が後から決まる配列は、宣言のときに要素の型を明示します。推論に任せる場所と自分で書く場所を分ける判断が、慣れるまでのつまずきどころです。