「明示型」と「推論型」とは何か
TypeScriptには、型を扱う2つのスタイルがあります。
ひとつは「明示型」——自分で : string や : number のように型を書いて宣言するやり方。
もうひとつは「推論型」——TypeScriptに「この値から型を判断して」と任せるやり方です。
// 明示型(explicit typing)
let age: number = 20;
// 推論型(type inference)
let score = 80; // TypeScript が number と推論
TypeScriptどちらも最終的には「age は number」「score も number」として扱われます。
違うのは、「人間が型を書くか」「コンパイラが型を決めるか」です。
明示型を使うべき典型的な場所
関数の引数と戻り値
関数の引数と戻り値は、「明示型」を強くおすすめする領域です。
function add(a: number, b: number): number {
return a + b;
}
TypeScriptここで大事なのは、コードを読むだけで「この関数は number を2つ受け取って、number を返す」と一目で分かること。
これは「設計の約束」を型で表現している状態です。
もし引数に型を書かないと、strict でなければ any になり、型安全性が一気に崩れます。
関数は「外から呼ばれる窓口」なので、ここを曖昧にすると、バグが入り込む余地が一気に増えます。
オブジェクトリテラルや重要な構造
ユーザー情報や設定など、「形が重要なオブジェクト」にも明示型を付ける価値が高いです。
type User = {
id: number;
name: string;
email: string;
};
const user: User = {
id: 1,
name: "Taro",
email: "taro@example.com"
};
TypeScriptこうしておくと、email を書き忘れたり、id に string を入れたりした瞬間にエラーになります。
「このオブジェクトはこういう形であるべき」という設計を、型として固定できるのが明示型の強みです。
推論型に任せていい場所
シンプルなローカル変数
一方で、すべてに : 型 と書く必要はありません。
特に、関数の中の「その場で完結するローカル変数」は、推論に任せた方が読みやすくなることが多いです。
const price = 1000; // number と推論
const taxRate = 0.1; // number と推論
const total = price * (1 + taxRate); // number と推論
TypeScriptここにわざわざ : number を全部書くと、情報量は増えますが、目線としては「もう分かってるよ」というノイズにもなりがちです。
TypeScript公式も、「初期化される変数やメンバー、デフォルト引数、戻り値などは、多くの場合推論で十分」と説明しています。
文脈から明らかなとき
たとえば、配列リテラルも中身から型が推論されます。
const scores = [80, 90, 100]; // number[] と推論
const names = ["Taro", "Hanako"]; // string[] と推論
TypeScript「全部数値」「全部文字列」と一目で分かる場面では、推論に任せてもコードの意図は十分伝わります。
明示型と推論型の「役割分担」の考え方
設計を表現したいところは明示型
ポイントは、「どこに“設計の意図”を刻みたいか」です。
関数の引数・戻り値
外部との境界(APIレスポンス、ライブラリとのやり取り)
ドメイン的に重要な型(User, Product, Config など)
こういう場所は、「この型であるべきだ」という意図を明示的に書いた方が、未来の自分や他人にとって圧倒的に読みやすくなります。
type ProductId = number;
function getProduct(id: ProductId): Promise<Product> {
// ...
}
TypeScriptここで id: ProductId と書いておくと、「ただの number じゃなくて、プロダクトIDなんだな」と分かります。
こういう「意味のある型」は、推論に任せず、明示的に書いた方が設計が伝わります。
実装の細部は推論に任せてスッキリさせる
逆に、関数の中の一時変数や、中間計算の結果など、「外から見えない実装の細部」は、推論に任せてしまって構いません。
function calcTotal(price: number, taxRate: number): number {
const tax = price * taxRate; // number と推論
const total = price + tax; // number と推論
return total;
}
TypeScriptここで tax: number や total: number と書いても間違いではありませんが、推論に任せた方がコードが軽くなり、「何をしているか」に集中しやすくなります。
「任せすぎる」と何が起きるか
any に落ちてしまう危険
推論に任せるときに一番怖いのは、「気づかないうちに any になっている」パターンです。
function greet(name) {
return `Hello, ${name}`;
}
TypeScript引数に型を書かないと、strict でなければ name は any になります。
any は「何でも入るし、何でもできる」代わりに、型チェックが効かなくなる危険な存在です。
なので、特に関数の引数は「推論に任せない」「必ず明示型を書く」と決めてしまった方が安全です。
初心者向けの実践ルール
最後に、現場でもそのまま通用するシンプルな指針をまとめると、こんな感じです。
関数の引数と戻り値:必ず明示型を書く。
オブジェクトの型(User, Product など):型エイリアスやinterfaceで明示的に定義する。
ローカル変数(関数の中):初期値がはっきりしているなら推論に任せてOK。
「意味を伝えたい場所」:明示型で意図を刻む。
「見れば分かる場所」:推論でコードを軽くする。
このバランスが取れてくると、
「型がうるさい」ではなく「型が設計を支えてくれている」感覚に変わっていきます。
