TypeScript | 基礎文法:関数の基礎 – 戻り値型の省略

TypeScript
スポンサーリンク

「戻り値型の省略」って、していいの?ダメなの?

まず結論から言うと、
TypeScript では 「戻り値型は省略しても動く」 し、「でも省略しない方がいい場面もたくさんある」 です。

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

この関数、戻り値型(): number)を書いていませんが、TypeScript は
a + b は number だから、この関数は number を返す」と自動で推論してくれます。

だから、技術的には「戻り値型は必須ではない」。
でも、「いつ省略してよくて、いつ書いた方がいいのか」 を感覚として持っておくことが、実務ではかなり大事になります。


TypeScript がやってくれる「戻り値型の推論」

単純な式なら、ほぼ正確に推論される

たとえば、こんな関数たち。

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

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

function isAdult(age: number) {
  return age >= 18;
}
TypeScript

TypeScript はそれぞれ、

  • add の戻り値型 → number
  • greet の戻り値型 → string
  • isAdult の戻り値型 → boolean

と推論してくれます。

つまり、「return の中身がシンプルな式なら、戻り値型を省略してもほぼ困らない」 ということです。

呼び出し側では、ちゃんと型が効きます。

const n = add(1, 2);      // n: number
const msg = greet("Taro"); // msg: string
const ok = isAdult(20);    // ok: boolean
TypeScript

ここまでは「省略してもいい世界」です。


省略したときに「危険」になりやすいパターン

途中で型が変わっても気づきにくくなる

例えば、こんな関数を考えます。

function getStatus(code: number) {
  if (code === 200) {
    return "ok";
  } else if (code === 404) {
    return "not_found";
  } else {
    return null;
  }
}
TypeScript

戻り値型を書いていないので、TypeScript は
"ok" | "not_found" | null のような型を推論してくれます(かなり賢いです)。

でも、あとからうっかりこう変えてしまったとします。

function getStatus(code: number) {
  if (code === 200) {
    return "ok";
  } else if (code === 404) {
    return "not_found";
  } else {
    return "error"; // なんとなく null をやめた
  }
}
TypeScript

このとき、戻り値型は "ok" | "not_found" | "error" に変わります。
呼び出し側で「null を考慮していたコード」があっても、コンパイルエラーにはなりません。

もし最初からこう書いていたらどうでしょう。

function getStatus(code: number): "ok" | "not_found" | null {
  // ...
}
TypeScript

この状態で return "error" と書いたら、即エラーになります。

「戻り値型を明示しておくと、“関数の約束”を勝手に変えたときに TypeScript が怒ってくれる」
これが、戻り値型を省略しない大きなメリットです。


「省略していい場面」と「書いた方がいい場面」

省略してもいい場面(練習・小さな関数)

例えば、ファイルの中だけで完結している、小さなユーティリティ関数。

function double(n: number) {
  return n * 2;
}

function toUpper(s: string) {
  return s.toUpperCase();
}
TypeScript

こういう「単純で、すぐ上に実装が見える関数」は、戻り値型を省略してもそこまで困りません。
読み手も「中身を見ればすぐ分かる」し、推論もほぼ正確です。

学習中にサクサク書きたいときも、ここは無理に書かなくていいです。
「まずは関数を書くことに慣れる」 ほうが大事なフェーズもあります。

書いた方がいい場面(実務・外から呼ばれる関数)

逆に、次のような関数は、戻り値型を明示した方がいいです。

アプリのあちこちから呼ばれる「サービス関数」
API クライアント(サーバーからデータを取ってくる関数)
ライブラリとして公開する関数
戻り値がオブジェクト・配列・ユニオン型など、少し複雑なもの

例えば、API クライアント。

async function fetchUser(id: string) {
  const res = await fetch(`/api/users/${id}`);
  const data = await res.json();
  return data;
}
TypeScript

これだと、戻り値型は any に近い扱いになってしまいがちです。
実務では、こう書きたいです。

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

async function fetchUser(id: string): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  const data = await res.json();
  return data as User;
}
TypeScript

ここで Promise<User> と書くことで、

「この関数を await したら、User 型が返ってくる」
「User にないプロパティを使おうとしたらエラーになる」

という世界が手に入ります。

「他のコードから見たときに、“この関数は何を返すのか”が一目で分かる」
これが、戻り値型を明示する一番の価値です。


戻り値型を省略したときの「落とし穴」になりがちな例

何も返さないつもりが、実は返してしまっている

function logAndCount(messages: string[]) {
  let count = 0;
  for (const m of messages) {
    console.log(m);
    count++;
  }
  return count;
}
TypeScript

この関数、名前だけ見ると「ログを出すだけ」に見えますが、実は数も返しています。
戻り値型を書いていないと、「戻り値を使う前提なのか、そうでないのか」が曖昧になります。

意図が「ログを出すだけ」なら、こう書いた方がいいです。

function logMessages(messages: string[]): void {
  for (const m of messages) {
    console.log(m);
  }
}
TypeScript

逆に、「数を返すことが大事」なら、こう。

function logAndCount(messages: string[]): number {
  let count = 0;
  for (const m of messages) {
    console.log(m);
    count++;
  }
  return count;
}
TypeScript

「この関数の“役割”は何か?」を戻り値型で表現する
その意識があると、省略するかどうかの判断も自然に決まってきます。


戻り値型を「書く練習」を少しだけしてみる

まずは「自分の頭の中のイメージ」をそのまま型にする

例えば、こんな関数を考えます。

function buildUser(id: number, name: string) {
  return {
    id,
    name,
    createdAt: new Date(),
  };
}
TypeScript

自分の頭の中では、きっとこう思っているはずです。

「id は number、name は string、createdAt は Date のオブジェクトを返している」

それをそのまま型にすると、こうです。

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

function buildUser(id: number, name: string): User {
  return {
    id,
    name,
    createdAt: new Date(),
  };
}
TypeScript

この「頭の中のイメージ → 型として書き下す」という練習をすると、
戻り値型を書くのがだんだん自然になってきます。


まとめ:戻り値型の省略は「サボり」ではなく「選択」

戻り値型を省略すること自体は、悪いことではありません。
TypeScript はかなり賢く推論してくれるので、特に小さな関数ではそれで十分なことも多いです。

でも、実務や少し大きめのコードになってくると、
「この関数は何を返すのか?」を明示しておくことが、設計の一部 になってきます。

だから、こんな感覚で使い分けるのがおすすめです。

練習中・小さな関数 → 省略してもOK。まずは書くことに慣れる。
他のコードからも呼ばれる関数 → 戻り値型を書いて、「約束」をはっきりさせる。
戻り値が複雑・重要 → 省略せず、むしろ積極的に型で表現する。

「この関数、何を返すつもりで書いてる?」
その問いに、自分でちゃんと答えられるようになったら、
戻り値型を書くか省略するかは、もうあなたの設計の選択です。

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