TypeScript | 基礎文法:変数・基本型 – 型推論の仕組み

TypeScript
スポンサーリンク

型推論とは何か

型推論(type inference)は、「あなたが書いたコードから、TypeScriptが自動的に型を推測してくれる仕組み」です。
毎回すべての変数や関数に型注釈を書かなくても、初期値や式の形から「これは number だな」「これは string の配列だな」と判断してくれます。

let age = 20;          // number と推論される
const name = "Taro";   // string と推論される
const flags = [true];  // boolean[] と推論される
TypeScript

ここでは一切 : number: string と書いていませんが、TypeScriptは内部的に「そういう型として扱う」と決めています。
この「自動で型が付く」おかげで、型安全性を保ちながら、コード量を増やしすぎずに済むわけです。


変数宣言における型推論

初期値から型を決める

もっとも基本的な型推論は、「変数の初期値から型を決める」というものです。

let count = 0;          // count: number
const title = "本";     // title: string
let isActive = true;    // isActive: boolean
TypeScript

count に数値リテラル 0 を入れたので、「これは number 型の変数だ」と推論されます。
その結果、あとから文字列を代入しようとするとエラーになります。

count = 1;      // OK
// count = "1"; // エラー
TypeScript

型注釈を書いたときと同じように、「一度 number と決めたら、ずっと number」として扱われるわけです。

const と let で推論のニュアンスが変わる

const の場合、値が変わらない前提なので、より「狭い」型に推論されることがあります。

const color = "red"; // "red" という文字列リテラル型として扱われることが多い
let color2 = "red";  // string として扱われる
TypeScript

const color は「一生 ‘red’ のまま」と分かっているので、「string 全体」ではなく「’red’ という値そのもの」として扱える場面があります。
一方 let はあとから変わる可能性があるので、「string 型」として少し広めに見ます。

この「どこまで狭く(具体的に)推論するか」は、TypeScriptのバージョンや設定にもよりますが、感覚として「const はより固く、let は少しゆるく」くらいで捉えておくとよいです。


式や演算からの型推論

計算結果から型を決める

TypeScriptは、単純なリテラルだけでなく、式の形からも型を推論します。

const price = 1000;
const taxRate = 0.1;
const total = price * (1 + taxRate); // total: number
TypeScript

ここでは、pricetaxRate も number と推論され、その掛け算・足し算の結果である total も number と推論されます。
このあと total = "1000"; のように書こうとすると、やはりエラーになります。

配列リテラルからの推論

配列も同様に、中身から型が推論されます。

const scores = [80, 90, 100];      // number[] と推論
const names = ["Taro", "Hanako"];  // string[] と推論
TypeScript

要素がすべて number なら number[]、すべて string なら string[] という具合です。
もし混在させると、より広い型(たとえば (number | string)[])として推論されます。

const mixed = [1, "2"]; // (number | string)[] と推論
TypeScript

この「混ざり方」も、TypeScriptがちゃんと見ています。


関数と型推論

戻り値の型推論

関数の戻り値も、return 文から推論されます。

function add(a: number, b: number) {
  return a + b;
}
TypeScript

ここでは戻り値に型注釈を書いていませんが、ab が number で、その足し算を返しているので、「戻り値は number」と推論されます。
呼び出し側では、const result = add(1, 2); と書いたとき、result は number として扱われます。

ただし、設計上大事な関数や外部に公開する関数では、あえて戻り値の型を明示することが多いです。

function add(a: number, b: number): number {
  return a + b;
}
TypeScript

こうしておくと、「この関数は必ず number を返す」という契約がよりはっきりします。

引数の型は推論されないことが多い

関数の引数については、基本的に「型注釈を書く」のが前提です。

function greet(name) {
  return `Hello, ${name}`;
}
TypeScript

このように書くと、name は any とみなされてしまい、型安全性が落ちます。
strict モードではエラーにもなります。

なので、関数の引数には、

function greet(name: string): string {
  return `Hello, ${name}`;
}
TypeScript

のように、きちんと型注釈を書くのが基本です。
「変数や戻り値は推論に任せてもいいけれど、引数は自分で型を書く」というのが、実務でもよくあるスタイルです。


型推論に任せていいところ・任せすぎてはいけないところ

任せていいところ

ローカル変数や、一目で型が分かるような単純な初期化には、型推論をどんどん使って構いません。

const message = "Hello"; // string と分かる
let count = 0;           // number と分かる
const items = [1, 2, 3]; // number[] と分かる
TypeScript

こういうところにまで毎回 : string: number[] と書くと、逆にノイズが増えて読みづらくなることもあります。

任せすぎると危ないところ

一方で、次のような場所は、型注釈を書いた方が安全です。

関数の引数・戻り値
外部との境界(APIレスポンス、ライブラリとのやり取りなど)
意味が重要な値(ID、フラグ、設定値など)

たとえば、ユーザー情報を返す関数なら、

type User = {
  id: number;
  name: string;
};

function getUser(): User {
  return { id: 1, name: "Taro" };
}
TypeScript

のように、「User を返す」と明示しておくと、実装を変えたときに型のズレがすぐに検出されます。
ここを推論に任せてしまうと、「たまたま今は合っているけど、将来ズレても気づきにくい」という状態になりがちです。


初心者がまず掴んでおきたい型推論の感覚

型推論は、「TypeScriptがいい感じに型を付けてくれる魔法」ではなく、「あなたが書いた情報から、論理的に型を決めている仕組み」です。

だからこそ、次のような感覚が大事になります。

初期値がはっきりしているローカル変数は、推論に任せてOK。
関数の引数・戻り値や、外部との境界は、自分で型を書く。
「この型であるべき」という意図を伝えたい場所には、あえて型注釈を書く。

このバランスが取れてくると、コードは短く、でも型はしっかり効いている——という気持ちいい状態になります。

タイトルとURLをコピーしました