【入門編】 型拡幅(Type Widening)の概念 – TypeScript実践ガイド

TypeScriptの「勝手に型が広がる」現象を攻略しよう!型拡幅(Type Widening)の正体

こんにちは!TypeScriptの世界へようこそ。
型定義を書き始めて、「あれ、さっき決めたはずの値なのに、なぜか型が変わっちゃってる?」と首を傾げたことはありませんか?

実はそれ、TypeScriptが親切心でやってくれている「型拡幅(Type Widening)」という挙動なんです。今日は、このちょっと不思議な現象を、日常の例え話を交えながら紐解いていきましょう。大丈夫、仕組みさえ分かれば怖くありませんよ!

—

1. 「お買い物」で例える型拡幅

想像してみてください。あなたは今、スーパーで「北海道産の牛乳」を1本だけ買おうとしています。

  • リテラル型: 「北海道産の牛乳」というピンポイントな指定。
  • 基本型(string): 「飲み物ならなんでもいいよ」という大雑把な括り。

TypeScriptは、変数に値を代入するとき、「今はこれだけど、後から他の種類も入るかもしれないよね?」と気を利かせて、わざと枠組みを大きく広げてしまうことがあります。

実際にコードで見てみましょう

// constで宣言すると、TypeScriptは「これは絶対変わらない値だ」と理解します
const milk = “北海道産牛乳”;
// 型は “北海道産牛乳” という「リテラル型」のまま固定されます。

// 一方、letで宣言すると……?
let drink = “北海道産牛乳”;
// 驚くことに、TypeScriptはこれを「string型(ただの文字列)」だと解釈します。
// なぜなら、「後で『オレンジジュース』に書き換えるかもしれないでしょ?」と考えているからです。

これが型拡幅(Type Widening)です。変数`drink`は、元々「北海道産牛乳」という特定の銘柄だったのに、いつの間にか「文字列全般」という広い世界に放り出されてしまったわけですね。

—

2. なぜ型が広がるのか?

開発現場でよくあるのが、「設定値」を定義しているときです。

let theme = “dark”; // 「dark」という特定のテーマを入れたい!
theme = “light”; // これはOK
theme = “banana”; // ええっ!?これも通っちゃうの!?

`theme`が`string`型に拡幅されてしまっているため、本来ありえない「banana」という値まで許容されてしまいます。これはバグの温床になりそうで少し不安ですよね。

—

3. 「広げないで!」を守るための3つのテクニック

安心してください。TypeScriptには「その箱、広げないで!」と指示する方法がちゃんと用意されています。

① `as const` を使う(一番おすすめ!)

最近の現場で最もよく使われるのが「定数アサーション」と呼ばれるこの記法です。

// as const をつけると「この値は二度と変えないし、型も広げない!」と宣言できます
const settings = {
theme: “dark”
} as const;

// settings.theme = “light”; // エラー!「dark」専用なので変更できません。
// これにより、意図しない値の混入を未然に防げます。

② 型を明示的に指定する

型を自分でしっかりと書くことで、TypeScriptの「気を利かせすぎた自動推論」を上書きします。

type Theme = “dark” | “light”; // 選択肢を自分で絞る

let myTheme: Theme = “dark”;
// これなら「dark」か「light」しか入りません。安心感が違いますね。

③ `as` でキャストする(最終手段)

どうしても型を狭めたいときに使いますが、少し強引な手法です。

let color = “red” as “red”;
// 「red」というリテラル型として強制的に扱います。

—

現場のアーキテクトからのアドバイス

TypeScriptが型を広げるのは、決して意地悪をしているわけではありません。「柔軟に変更できるようにしておく方が、開発者が楽だろう」という、プログラミング言語なりの優しさなんです。

ただ、私たちの現場では「予測可能であること」が何よりの正義。

  • 値が変わらないなら `const` + `as const`
  • 選択肢が決まっているなら型エイリアス(`type`)

この2つを使いこなすだけで、あなたの書くコードはぐっと堅牢で、他のメンバーからも「おっ、分かってるね!」と思われるものに変わります。

最初は難しく感じるかもしれませんが、まずは「変数を定義するとき、TypeScriptは空気を読もうとしてくれているんだな」と想像してみてください。それだけで、エラーメッセージとの向き合い方が少し温かいものになるはずですよ。

それでは、良いTypeScriptライフを!何か分からないことがあったら、いつでも聞いてくださいね。

コメント

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