TypeScriptの基本的な型は覚えたけど、実際のコードに出てくる <T>| を見ると「これ何…?」となること、ありますよね。

string | number って書いてあるけど、これどういう意味?
関数に <T> が付いてるの、読もうとしても全然わからない…
enumとas constどっちを使えばいいのか、調べても結局よくわからなかった

この記事では、TypeScriptの「型の応用」に入ったときに最初につまずきやすいテーマをまとめて整理します。ユニオン型と型ガード、ジェネリクスの考え方、enumとas constの使い分けの概要、ユーティリティ型の全体像といった内容を、順番に解説していきます。

この記事は次のような方におすすめです。

この記事はこんな人におすすめ!
  • string / number / boolean などの基本の型は理解している
  • interfaceやtypeエイリアスは一通り触れたことがある
  • 実際のコードで <T>| を見て意味が追えなかった経験がある
  • 「型の基礎の次に何を学べばいいか」を整理したい

この記事を読むと、TypeScriptの型応用機能がどんな構造になっているかの全体像がつかめます。それぞれのテーマで「何のためにあるか」がわかれば、各機能を詳しく学ぶときにぐっとスムーズになります。

それでは、順を追って詳しく見ていきましょう!

まずは動画解説を観る

ユニオン型と型ガード — 複数の型を受け入れて安全に絞り込む

ユニオン型は「この変数にはstringかnumberのどちらかが入る」という書き方をするときに使います。柔軟に見えますが、実は「そのまま使うと型エラーが出る」という問題が生まれます。その解決策が型ガードです。この2つはセットで理解するのがポイントです。

ユニオン型の基本的な書き方

ユニオン型は |(パイプ)を使って複数の型を並べる構文です。

// 引数が string か number のどちらかを受け取る関数
function printValue(value: string | number): void {
  console.log(value);
}

printValue("hello"); // OK
printValue(42);      // OK

string | number のように書くと「どちらの型も受け入れる」という意味になります。 関数の引数はもちろん、変数の型定義にも使えます。

let id: string | number;
id = "user-001"; // OK
id = 123;        // OK

ユニオン型を使うとエラーが出る場面と、型ガードの必要性

ここが最初のつまずきポイントです。ユニオン型で受け取った値に対して、型固有のメソッドを呼ぼうとするとエラーになります。

function printValue(value: string | number): void {
  console.log(value.toUpperCase()); // エラー!
  // Property 'toUpperCase' does not exist on type 'string | number'
}

toUpperCase() はstringにしかないメソッドです。TypeScriptは「valueがnumberかもしれない」と知っているので、エラーを出します。

TypeScriptに「今この時点ではstringだよ」と伝える必要があります。 それが型ガードの役割です。

typeofを使った型ガードの基本

型ガードとは、「ある条件の中ではこの型だ」とTypeScriptに認識させる書き方です。typeof を使った条件分岐が最もシンプルなパターンです。

function printValue(value: string | number): void {
  if (typeof value === "string") {
    // このブロックの中では、value は string 型として扱われる
    console.log(value.toUpperCase()); // OK
  } else {
    // このブロックの中では、value は number 型として扱われる
    console.log(value.toFixed(2)); // OK
  }
}

if (typeof value === "string") の条件分岐の中では、TypeScriptがvalueをstring型として認識してくれます。これを「型の絞り込み(narrowing)」と言います。

整理すると、ユニオン型で「どちらの型も受け入れる」を実現して、型ガードで「今どの型かを確定させる」という2段階で使います。

なかむぅ
なかむぅ
ユーザー定義型ガードやより複雑な型の絞り込みについては、別の記事で詳しく解説しています。
TypeScriptのユニオン(Union)型とは?型ガードで「どの型か」を安全に絞り込む方法
TypeScriptのユニオン(Union)型とは?型ガードで「どの型か」を安全に絞り込む方法TypeScriptのユニオン型とは何かを基礎から解説。typeof・in・instanceofを使った型ガードの違いと使い分けも初心者向けにわかりやすく整理します。...

ジェネリクスとは — 型を「後から決める」仕組み

ジェネリクスは「型の引数」を持つ仕組みです。「型を引数として受け取る」とはどういうことか、問題から考えると理解しやすくなります。

ジェネリクスを使わないとどうなるか

たとえば、配列から先頭の要素を返すだけのシンプルな関数を書くとします。

// string の配列用
function firstString(arr: string[]): string {
  return arr[0];
}

// number の配列用
function firstNumber(arr: number[]): number {
  return arr[0];
}

やっていることは同じなのに、型ごとに関数を作らないといけません。any を使えば1つにまとめられますが、今度は型の情報が失われます。

function first(arr: any[]): any {
  return arr[0];
}

const result = first(["a", "b", "c"]);
// result の型が any になってしまう
// 戻り値が string だとわかっているのに、TypeScript が追跡してくれない

any を使うと「TypeScriptが型を追跡できなくなる」という問題が起きます。 これがジェネリクスの必要性が生まれる理由です。

<T> の読み方と基本構文

ジェネリクスは <T> という記法で型を「後から受け取る」ことができます。

function first<T>(arr: T[]): T {
  return arr[0];
}

<T> は「型の仮引数」です。関数を呼び出すときに型が決まります。T は慣例的な名前で、実際には任意の名前が使えます(ItemValue でも構いません)。

ジェネリクスを使うとどう変わるか

先ほどの first 関数を使ってみます。

const result1 = first(["a", "b", "c"]); // result1 の型は string
const result2 = first([1, 2, 3]);        // result2 の型は number

TypeScriptが引数の型から T を自動的に推論してくれるので、first<string>(...) のように明示しなくても動きます。戻り値の型も stringnumber として正しく認識されます。

「同じ処理を型ごとに書き分けなくていい、かつ型の情報も失われない」というのがジェネリクスのメリットです。

なかむぅ
なかむぅ
制約付きジェネリクス(T extends ... を使う書き方)や複数の型引数を使う応用は、別の記事で詳しく解説しています。
【TypeScript】ジェネリクス(generics)とは?書き方と3つの使いどころ
【TypeScript】ジェネリクス(generics)とは?書き方と3つの使いどころTypeScriptのジェネリクスとは何かを初心者向けに解説。の意味、anyとの違い、書き方や使いどころまでやさしく理解できます。...

enumとas const — 列挙型の使い方と使い分けの概要

「決まった値のセット」を定義したいときに使うのがenumです。JavaScriptにはない機能ですが、「非推奨では?」という話を見かけることもあります。ここではその背景をざっくり整理します。

enumの基本と使いどころ

enumは「いくつかの決まった値の中から1つを選ぶ」型を作るときに使います。

enum Direction {
  Up    = "UP",
  Down  = "DOWN",
  Left  = "LEFT",
  Right = "RIGHT",
}

function move(dir: Direction): void {
  console.log(dir);
}

move(Direction.Up); // "UP"

方角・ステータス・処理結果など、「取りうる値が固定されている」ケースで使われます。定義した値以外は渡せないので、うっかりミスを防げます。

as constとの使い分けを一言で整理する

enumの問題点の1つは、「JavaScriptにコンパイルすると余分なコードが生成される」点です。その代替としてよく使われるのが as const を使ったオブジェクトです。

const Direction = {
  Up:    "UP",
  Down:  "DOWN",
  Left:  "LEFT",
  Right: "RIGHT",
} as const;

type Direction = typeof Direction[keyof typeof Direction];
// "UP" | "DOWN" | "LEFT" | "RIGHT" というユニオン型になる

「enumは手軽だが生成コードが増える。as constはオブジェクトベースで軽量」という感覚的な差があります。

なかむぅ
なかむぅ
どちらをいつ使うかの詳細な判断基準は、別の記事で整理しています。
TypeScriptのenumは非推奨?使い方と代わりの書き方をわかりやすく解説
TypeScriptのenumは非推奨?使い方と代わりの書き方をわかりやすく解説TypeScriptのenumは本当に非推奨なのか。基本の使い方から問題点、代替手段まで初心者にもわかりやすく整理して解説します。...
なかむぅ
なかむぅ
as constそのものの仕組みについては、こちらの記事で詳しく解説しています。
TypeScriptのas constとは?具体的な使い方と2つの注意点TypeScriptのコードを読んでいると、as const という見慣れない記述に出くわすことがあります。 この...

ユーティリティ型とは — TypeScript組み込みの型変換ツール

ユーティリティ型は、TypeScriptに最初から組み込まれている「型を変換するツール群」です。既存の型を元に「一部をオプショナルにした型」「一部のプロパティだけ取り出した型」などを作ることができます。

よく使うユーティリティ型の一覧

型名 概要 よく使う場面のイメージ
Partial<T> 全プロパティをオプショナルにする 更新APIの引数など「一部だけ渡す」ケース
Required<T> 全プロパティを必須にする オプショナルを消したい場面
Readonly<T> 全プロパティを読み取り専用にする 変更不可のデータを扱う場面
Pick<T, K> 指定したプロパティだけを取り出す 必要な項目だけの型を作りたい場面
Omit<T, K> 指定したプロパティを除外する 特定のキーだけ省いた型を作りたい場面
Record<K, V> キーと値の型を指定したオブジェクト型を作る マップ・辞書型の型定義

簡単なコード例を見てみましょう。

interface User {
  id: number;
  name: string;
  email: string;
}

// id と name だけを持つ型を作る
type UserPreview = Pick<User, "id" | "name">;
// → { id: number; name: string; }

// 全プロパティをオプショナルにした型を作る
type PartialUser = Partial<User>;
// → { id?: number; name?: string; email?: string; }

既存の型を元に、派生した型を手軽に作れるのが特徴です。

ユーティリティ型はなぜ便利か

たとえばAPIのレスポンス型と更新リクエストの型が「ほぼ同じだけど一部違う」という状況はよくあります。

ユーティリティ型を使うと、似た型を何度も手書きせずに既存の型から派生させられます。 型の定義が1か所にまとまるので、型が変わったときの修正コストも下がります。

ユーティリティ型は「暗記するもの」というより「一覧を見て必要なときに使うもの」だと思っておくと楽です。

なかむぅ
なかむぅ
各ユーティリティ型の詳細な使い方は、別の記事で解説しています。
TypeScriptでよく使う5つのユーティリティ型(utility types)の使い方TypeScriptのユーティリティ型を初心者向けに解説。Partial・Pick・Omitなど、よく使う5つの型の意味と使い分けがすっきりわかります。...

タグ付きユニオン(Discriminated Union)とは何か

ユニオン型をより安全に使いこなすパターンとして、「タグ付きユニオン」があります。

ユニオン型で複数の型を受け入れるとき、「今どの型なのか」を識別するための共通プロパティ(タグ)を持たせる、という設計です。

type SuccessResult = {
  status: "success"; // タグ(識別用のリテラル型)
  data: string;
};

type ErrorResult = {
  status: "error"; // タグ
  message: string;
};

type Result = SuccessResult | ErrorResult;

status というリテラル型のプロパティを共通で持つことで、status === "success" の条件分岐の中でTypeScriptが型を自動的に絞り込んでくれます。

なかむぅ
なかむぅ
「typeofで判断できないオブジェクト型のユニオン型」を扱うときに特に有効なパターンです。パターンの詳細や応用については、別の記事で解説しています。
【TypeScript】Discriminated Unionとは?タグで型を絞り込む仕組みを解説TypeScriptのDiscriminated Unionを初心者向けに解説。タグによる型の絞り込み、switch文、never型の使い方までやさしく理解できます。...

never型とは — 「ありえない型」が役立つ場面

never型は「値が存在しない」「絶対に到達しない」状態を表す型です。void(何も返さない)とは意味が違います。

  • void:関数が「値を返さない」(処理は終わる)
  • never:関数が「絶対に正常終了しない」(例外を投げるなど)
// void の例:戻り値がない関数
function log(message: string): void {
  console.log(message);
}

// never の例:必ず例外を投げる関数
function throwError(message: string): never {
  throw new Error(message);
  // この行には絶対に到達しない
}

never型が実用的に使われる場面の1つが、ユニオン型の「全パターンを網羅しているか」のチェックです。

type Color = "red" | "blue" | "green";

function handleColor(color: Color): string {
  if (color === "red")   return "赤";
  if (color === "blue")  return "青";
  if (color === "green") return "緑";

  // ここに到達することはないはず → never で網羅チェック
  const _exhaustive: never = color;
  return _exhaustive;
}

後から Color に新しい値を追加したときに、ここでエラーが出るようになります。処理漏れを型レベルで防げるのが便利なところです。

なかむぅ
なかむぅ
exhaustive checkなど詳細な使い方は、別の記事で解説しています。
TypeScriptのnever型 — 3つの登場シーンと使い所をわかりやすく解説TypeScriptを使っていると、ふとしたタイミングでコードの中に never という型が出てくることがあります。 ...

まとめ — ピラー6で扱った型応用の全体像

この記事では、TypeScriptの「型の応用」に入ったときに出会う主な機能を一通り見てきました。

  • ユニオン型は「複数の型のどちらかを受け入れる」書き方。| でつなぐ
  • 型ガードは「今どの型かをTypeScriptに教える」仕組み。typeof を使った条件分岐が基本
  • ジェネリクスは「型を後から受け取る」仕組み。<T> を使って汎用的な関数・型を作れる
  • enumは「決まった値のセット」を定義する型。as constによる代替パターンもある
  • ユーティリティ型は「既存の型を変換するツール群」。Partial・Pick・Omit・Recordなどがある
  • タグ付きユニオンは、共通のリテラル型プロパティを使ってユニオン型の絞り込みを安全にするパターン
  • never型は「到達しない」を表す型で、ユニオン型の網羅チェックに使える

「型の基礎(string / number / booleanやinterfaceなど)」を押さえた次のステップとして、この記事で挙げた機能がどんな場面で役立つかのイメージが持てれば十分です。

なかむぅ
なかむぅ
各テーマは以下の記事でより詳しく解説しています。気になるところから読んでみてください。
TypeScriptのユニオン(Union)型とは?型ガードで「どの型か」を安全に絞り込む方法
TypeScriptのユニオン(Union)型とは?型ガードで「どの型か」を安全に絞り込む方法TypeScriptのユニオン型とは何かを基礎から解説。typeof・in・instanceofを使った型ガードの違いと使い分けも初心者向けにわかりやすく整理します。...
【TypeScript】ジェネリクス(generics)とは?書き方と3つの使いどころ
【TypeScript】ジェネリクス(generics)とは?書き方と3つの使いどころTypeScriptのジェネリクスとは何かを初心者向けに解説。の意味、anyとの違い、書き方や使いどころまでやさしく理解できます。...
TypeScriptのenumは非推奨?使い方と代わりの書き方をわかりやすく解説
TypeScriptのenumは非推奨?使い方と代わりの書き方をわかりやすく解説TypeScriptのenumは本当に非推奨なのか。基本の使い方から問題点、代替手段まで初心者にもわかりやすく整理して解説します。...
TypeScriptでよく使う5つのユーティリティ型(utility types)の使い方TypeScriptのユーティリティ型を初心者向けに解説。Partial・Pick・Omitなど、よく使う5つの型の意味と使い分けがすっきりわかります。...
TypeScriptのas constとは?具体的な使い方と2つの注意点TypeScriptのコードを読んでいると、as const という見慣れない記述に出くわすことがあります。 この...
【TypeScript】Discriminated Unionとは?タグで型を絞り込む仕組みを解説TypeScriptのDiscriminated Unionを初心者向けに解説。タグによる型の絞り込み、switch文、never型の使い方までやさしく理解できます。...
TypeScriptのnever型 — 3つの登場シーンと使い所をわかりやすく解説TypeScriptを使っていると、ふとしたタイミングでコードの中に never という型が出てくることがあります。 ...