前提:「全部書く」か「全部省略」か、の二択ではない
まず大事なのは、
戻り値型は「常に書くべき」でも「常に省略すべき」でもない、ということです。
すでに話してきたように、
外部公開の関数・複雑な処理・ジェネリクスなどは「明示した方がいい場面」でした。
ここでは逆に、
「ここは素直に型推論に任せた方が、読みやすくて健全だよ」という場面を整理します。
キーワードは、
短い・局所的・文脈がはっきりしている、です。
パターン1:その場限りの小さなアロー関数(特にコールバック)
map / filter / forEach などの中の一行関数
一番典型的なのが、配列メソッドのコールバックです。
const numbers = [1, 2, 3];
const doubled = numbers.map((n) => n * 2);
TypeScriptここで戻り値型をわざわざ書くと、こうなります。
const doubled = numbers.map((n): number => n * 2);
TypeScriptもちろん間違いではありませんが、
読みやすさという意味では、ほとんど情報量が増えていません。
なぜかというと、
numbers が number[] なので、n は number と推論される
n * 2 は number なので、戻り値も number と分かる
map の戻り値は number[] と型定義に書いてある
という「文脈」がすでに十分だからです。
このように、
配列の map / filter / reduce などの中で使う
1〜数行程度の小さなアロー関数
引数の型が文脈から明らかで、戻り値も単純な式
という条件がそろっているときは、
戻り値型は省略してしまった方が、コードがスッキリします。
「読めば一瞬で分かる型」を、わざわざ文字として重ねない、という感覚です。
パターン2:ローカル関数で、処理も型も単純なとき
ファイルの中だけで完結する、小さな補助関数
例えば、ある関数の中でだけ使う「ちょっとした補助関数」。
function main() {
function toUpper(value: string) {
return value.toUpperCase();
}
console.log(toUpper("hello"));
}
TypeScriptここで toUpper の戻り値型は、string と書いてもいいですが、省略してもほぼ困りません。
理由はシンプルで、
引数が stringvalue.toUpperCase() の戻り値も string
toUpper 自体が main の中だけで使われている
という状況だからです。
「この関数は外から呼ばれない」「このスコープの中だけで完結している」
かつ「処理も型も単純」なローカル関数は、
戻り値型を省略しても、設計上のリスクはほとんどありません。
むしろ、
「ローカルな細かいところまで型注釈だらけ」になると、
本当に見たい“重要な型”が埋もれてしまいます。
局所的で単純な関数は、
推論に任せてコードを軽くしておく、というバランス感覚が大事です。
パターン3:テストコード・サンプルコード・一時的なスクリプト
「仕様を固定する」必要がないコード
例えば、テストコードの中でだけ使う関数。
function createUser(name: string) {
return {
id: 1,
name,
};
}
TypeScriptここで戻り値型を厳密に定義してもいいですが、
テストの文脈では「このファイルの中でしか使わない」「仕様として公開しない」ことが多いです。
サンプルコードや、
一時的に動かしてみるスクリプトも同じです。
こういうコードは、
長期的に保守する前提ではない
外部から再利用される前提でもない
ので、
戻り値型を省略して「とにかく挙動を確認する」ことを優先しても構いません。
もちろん、
テストコードでも型をきっちり書くスタイルもありますが、
初心者のうちは「本番コードの設計」に意識を集中させて、
テストやサンプルでは推論に甘える、という割り切りもアリです。
パターン4:ジェネリクスを使わない、単純な関数宣言
中身を見れば一瞬で分かる戻り値型
例えば、こんな関数。
function add(a: number, b: number) {
return a + b;
}
TypeScript戻り値型は number です。
書くとこうなります。
function add(a: number, b: number): number {
return a + b;
}
TypeScriptどちらでもいいのですが、
「引数の型が単純」「戻り値も単純」「外部公開の“顔”でもない」
という条件なら、省略しても大きな問題にはなりません。
特に、
小さなアプリや学習用コードでは、
こういうレベルの関数にいちいち戻り値型を書くよりも、
「どんな関数をどう分割するか」という設計そのものに意識を割いた方が、成長につながります。
もちろん、
「外部に export する」「ライブラリ的に使う」関数になった瞬間に、
戻り値型を明示する側に切り替える、という線引きができていれば十分です。
パターン5:アロー関数で「引数型だけ明示」している場合
「引数は自分で決める、戻り値は推論に任せる」という分担
例えば、文脈のないアロー関数。
const double = (x: number) => x * 2;
TypeScriptここで戻り値型は number ですが、
わざわざ : number と書かなくても、x * 2 から自動で推論されます。
この「引数だけ型を書く」スタイルは、
アロー関数と相性がとても良いです。
引数の型は、自分の意図をはっきりさせるために明示する
戻り値の型は、式から推論させてコードを軽くする
という役割分担ができるからです。
特に、
「引数が1〜2個」「戻り値が単純な式」というアロー関数では、
このスタイルが一番読みやすくなります。
戻り値型を省略しても、
関数全体の型は (x: number) => number としてちゃんと推論されるので、
型安全性が落ちるわけではありません。
逆に「省略しない方がいい」境界線を意識しておく
ここまで「省略していい場面」を見てきましたが、
実は判断の軸はシンプルです。
戻り値型を省略しても、
その関数の「役割」「危険性」「仕様」が、
呼び出し側から見て十分に伝わるか?
という問いです。
その場限り・局所的・単純・文脈が強い
→ 省略しても読みやすさが勝つ
外部公開・複雑・失敗を含む・ジェネリクスを使う
→ 明示しておいた方が設計意図が守られる
この線引きさえ頭に置いておけば、
「全部書くべきか?」「全部省略していいのか?」で迷わなくなります。
まとめ:「戻り値型を省略すべき場面」を自分の言葉で言うと
最後に、あなた自身の言葉でこう整理してみてください。
戻り値型を省略していいのは、
その関数がローカルで、小さくて、処理も型も一目で分かるとき
配列の map / filter などのコールバックのように、文脈から型が明らかなとき
テスト・サンプル・一時スクリプトのように、「仕様として固定する必要」が薄いとき
アロー関数で、引数型だけ明示しておけば、戻り値は式から自明なとき
そして大事なのは、
「省略するかどうか」を、
めんどくさいからではなく、
“この関数の役割とリスクを考えたうえでの選択”として決めること。
コードを書きながら、
「この関数の戻り値、型として“見える化”しておいた方が、未来の自分は楽になるかな?」
と一度だけ自分に聞いてみてください。
その一呼吸が、
戻り値型を「書く/書かない」を使い分けられるエンジニアへの分かれ目になります。
