my.code(); Logomy.code();
TypeScript-4.型を組み合わせる

my.code(); Logomy.code();

  • C++
    • 0.C++の世界へようこそ
    • 1.型システムと制御構造
    • 2.データ集合とモダンな操作
    • 3.ポインタとメモリ管理
    • 4.関数と参照渡し
    • 5.プロジェクトの分割とビルド
    • 6.クラスの基礎
    • 7.クラスを使いこなす
    • 8.継承とポリモーフィズム
    • 9.テンプレート
    • 10.STL ①:コンテナ
    • 11.STL ②:アルゴリズムとラムダ式
    • 12.RAIIとスマートポインタ
  • JavaScript
    • 0.JavaScriptへようこそ
    • 1.基本構文とデータ型
    • 2.制御構文
    • 3.関数とクロージャ
    • 4.'this'の正体
    • 5.オブジェクトとプロトタイプ
    • 6.クラス構文
    • 7.配列とイテレーション
    • 8.非同期処理①: Promise
    • 9.非同期処理②: Async/Await
  • Python
    • 0.環境構築と基本思想
    • 1.基本構文とデータ型
    • 2.リスト、タプル、辞書、セット
    • 3.制御構文と関数
    • 4.モジュールとパッケージ
    • 5.オブジェクト指向プログラミング
    • 6.ファイルの入出力とコンテキストマネージャ
    • 7.例外処理
    • 8.ジェネレータとデコレータ
  • Ruby
    • 0.rubyの世界へようこそ
    • 1.基本構文とデータ型
    • 2.制御構造とメソッド定義
    • 3.すべてがオブジェクト
    • 4.コレクション (Array, Hash, Range)
    • 5.ブロックとイテレータ
    • 6.クラスとオブジェクト
    • 7.モジュールとMix-in
    • 8.Proc, Lambda, クロージャ
    • 9.標準ライブラリの活用
    • 10.テスト文化入門
    • 11.メタプログラミング入門
  • Rust
    • 0.Rustの世界へようこそ
    • 1.基本構文と「不変性」
    • 2.関数と制御フロー
    • 3.所有権
    • 4.借用とスライス
    • 5.構造体とメソッド構文
    • 6.列挙型とパターンマッチ
    • 7.モジュールシステムとパッケージ管理
    • 8.コレクションと文字列
    • 9.エラーハンドリング
    • 10.ジェネリクスとトレイト
    • 11.ライフタイム
  • TypeScript
    • 0.TypeScriptへようこそ
    • 1.基本的な型と型推論
    • 2.オブジェクト、インターフェース、型エイリアス
    • 3.関数の型定義
    • 4.型を組み合わせる
    • 5.ジェネリクス
    • 6.クラスとアクセス修飾子
    • 7.非同期処理とユーティリティ型
my.code(); Logomy.code();

環境構築不要、その場で実践。

ut-code / my-code

Copyright © 2026 ut.code();

my.code(); について
コード実行環境についてAI質問機能についてライセンスお問い合わせ
ut.code(); について
公式ウェブサイト公式 𝕏 アカウント

第4章: 型を組み合わせる

これまでの章では、string や number、あるいは特定のオブジェクトの形といった「単一の型」を扱ってきました。しかし、現実のアプリケーション開発(特にJavaScriptの世界)では、「IDは数値かもしれないし、文字列かもしれない」「成功時はデータを返すが、失敗時はエラーメッセージを返す」といった柔軟なデータ構造が頻繁に登場します。

この章では、既存の型をパズルのように組み合わせて、より複雑で柔軟な状況を表現する方法を学びます。

Union型 (共用体型)

Union型(共用体型)は、「A または B」という状態を表現します。パイプ記号 | を使用して記述します。

JavaScriptでは変数の型が動的であるため、1つの変数に異なる型の値が入ることがよくありますが、TypeScriptではUnion型を使ってこれを安全に定義できます。

ファイルを編集:union-basic.ts
// idは数値、または文字列を許容する
let id: number | string;

id = 101;      // OK
id = "user-a"; // OK
// id = true;  // Error: Type 'boolean' is not assignable to type 'string | number'.

function printId(id: number | string) {
  console.log(`Your ID is: ${id}`);
}

printId(123);
printId("ABC");
npx tsc union-basic.ts && node union-basic.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のunion-basic.tsに書かれている内容を実行します。
Your ID is: 123
Your ID is: ABC
出力されたファイル(編集不可):union-basic.js

注意点: Union型を使用している変数は、その時点では「どの型か確定していない」ため、すべての候補に共通するプロパティやメソッドしか操作できません。特定の型として扱いたい場合は、後述する「型ガード」を使用します。

Literal型 (リテラル型)

string や number は「あらゆる文字列」や「あらゆる数値」を受け入れますが、「特定の値だけ」を許可したい場合があります。これをLiteral型(リテラル型)と呼びます。

通常、Literal型は単独で使うよりも、Union型と組み合わせて「決まった選択肢のいずれか」を表現するのによく使われます(Enumの代わりとしてもよく利用されます)。

ファイルを編集:literal-types.ts
// 文字列リテラル型とUnion型の組み合わせ
type TrafficLight = 'red' | 'yellow' | 'green';

let currentLight: TrafficLight = 'red';

// currentLight = 'blue'; // Error: Type '"blue"' is not assignable to type 'TrafficLight'.

// 数値リテラルも可能
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
let dice: DiceRoll = 3;

console.log(`Light: ${currentLight}, Dice: ${dice}`);
npx tsc literal-types.ts && node literal-types.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のliteral-types.tsに書かれている内容を実行します。
Light: red, Dice: 3
出力されたファイル(編集不可):literal-types.js

Intersection型 (交差型)

Intersection型(交差型)は、「A かつ B」を表します。アンパサンド & を使用します。 これは主にオブジェクトの型定義を合成(マージ)して、「複数の型のすべてのプロパティを持つ新しい型」を作る際によく使用されます。

ファイルを編集:intersection-types.ts
type Person = {
  name: string;
};

type Employee = {
  employeeId: number;
  department: string;
};

// Person かつ Employee の特徴を持つ型
type CompanyMember = Person & Employee;

const member: CompanyMember = {
  name: "Suzuki",
  employeeId: 5001,
  department: "Engineering"
  // どれか一つでも欠けるとエラーになります
};

console.log(member);
npx tsc intersection-types.ts && node intersection-types.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のintersection-types.tsに書かれている内容を実行します。
{ name: 'Suzuki', employeeId: 5001, department: 'Engineering' }
出力されたファイル(編集不可):intersection-types.js

補足: プリミティブ型同士で string & number のように交差させると、両方を満たす値は存在しないため、型は never(ありえない値)になります。Intersection型は主にオブジェクト型の合成に使われます。

null と undefined

TypeScriptには null 型と undefined 型が存在します。 tsconfig.json の設定で strictNullChecks: true(推奨設定)になっている場合、これらは他の型(stringなど)には代入できません。

値が存在しない可能性がある場合は、Union型を使って明示的に null や undefined を許可します。

ファイルを編集:nullable.ts
// string または null を許容する
let userName: string | null = "Tanaka";

userName = null; // OK

// オプショナルなプロパティ(?)は 「型 | undefined」 の糖衣構文に近い動きをします
type UserConfig = {
  theme: string;
  notification?: boolean; // boolean | undefined
};

const config: UserConfig = {
  theme: "dark"
  // notification は省略可能 (undefined)
};

console.log(`User: ${userName}, Theme: ${config.theme}`);
npx tsc nullable.ts && node nullable.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のnullable.tsに書かれている内容を実行します。
User: null, Theme: dark
出力されたファイル(編集不可):nullable.js

型ガード (Type Guards)

Union型 (string | number) の変数があるとき、プログラムの中で「今は string なのか number なのか」を区別して処理を分けたい場合があります。これを型の絞り込み(Narrowing)と言います。

TypeScriptのコンパイラが「このブロック内ではこの変数はこの型だ」と認識できるようにするチェック処理を型ガードと呼びます。

typeof 演算子

プリミティブ型(string, number, boolean, symbol, undefined)の判定に使います。

ファイルを編集:type-guard-typeof.ts
function formatPrice(price: number | string) {
  // ここでは price は number | string

  if (typeof price === 'string') {
    // このブロック内では price は 'string' 型として扱われる
    return parseInt(price).toLocaleString();
  } else {
    // このブロック内では price は 'number' 型として扱われる
    return price.toLocaleString();
  }
}

console.log(formatPrice(10000));
console.log(formatPrice("20000"));
npx tsc type-guard-typeof.ts && node type-guard-typeof.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のtype-guard-typeof.tsに書かれている内容を実行します。
10,000
20,000
出力されたファイル(編集不可):type-guard-typeof.js

in 演算子

オブジェクトが特定のプロパティを持っているかどうかで型を絞り込みます。

ファイルを編集:type-guard-in.ts
type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ('swim' in animal) {
    // ここでは Fish 型
    animal.swim();
  } else {
    // ここでは Bird 型
    animal.fly();
  }
}

const fish: Fish = { swim: () => console.log("Swimming...") };
move(fish);
npx tsc type-guard-in.ts && node type-guard-in.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のtype-guard-in.tsに書かれている内容を実行します。
Swimming...
出力されたファイル(編集不可):type-guard-in.js

instanceof 演算子

クラスのインスタンスかどうかを判定します(第7章のクラスで詳しく扱いますが、Dateなどの組み込みオブジェクトでも有効です)。

ファイルを編集:type-guard-instanceof.ts
function logDate(value: string | Date) {
  if (value instanceof Date) {
    console.log(value.toISOString());
  } else {
    console.log(value);
  }
}
出力されたファイル(編集不可):type-guard-instanceof.js

型アサーション (Type Assertions)

時に、プログラマがTypeScriptコンパイラよりも型の詳細を知っている場合があります。例えば、外部APIからのレスポンスや、DOM要素の取得などです。

as キーワードを使うと、コンパイラに対して「この変数はこの型であるとして扱ってくれ」と強制できます。

ファイルを編集:assertion.ts
// unknown型は何でも入るが、そのままでは操作できない型
let someValue: unknown = "This is a string";

// コンパイラに「これはstringだからlengthを使わせて」と伝える
let strLength: number = (someValue as string).length;

console.log(strLength);

// 注意: 全く互換性のない型への変換はエラーになりますが、
// unknownを経由すると無理やり変換できてしまうため、乱用は避けてください。
// let wrong = (123 as string); // Error
// let dangerous = (123 as unknown as string); // OKだが実行時にバグの元
npx tsc assertion.ts && node assertion.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のassertion.tsに書かれている内容を実行します。
16
出力されたファイル(編集不可):assertion.js

注意: 型アサーションはあくまで「コンパイル時の型チェックを黙らせる」機能であり、実行時の型変換を行うわけではありません。実行時に値が想定と違う場合、クラッシュの原因になります。可能な限り、型ガードを使って安全に絞り込むことを推奨します。

この章のまとめ

  • Union型 (|): 複数の型のうち「いずれか」を表す。
  • Literal型: 特定の値のみを許容する型。Union型と組み合わせて列挙型のように使える。
  • Intersection型 (&): 複数の型を「合成」して、すべてのプロパティを持つ型を作る。
  • null / undefined: strictNullChecks 環境下では、Union型を使って明示的に許容する必要がある。
  • 型ガード: typeof, in, instanceof などを使って、Union型から特定の型へ絞り込む。
  • 型アサーション (as): 型を強制的に指定するが、安全性のために使用は慎重に行う。

練習問題1: 結果の型定義

APIリクエストの結果を表す Result 型を定義してください。

  • 成功時は success: true と data: string を持ちます。
  • 失敗時は success: false と error: string を持ちます。
  • handleResult 関数内で型ガードを使い、成功ならデータを、失敗ならエラーメッセージをログ出力してください。
ファイルを編集:practice5_1.ts
// ここに SuccessResult, FailureResult, Result 型を定義してください
// type Result = ...

function handleResult(result: Result) {
  // ここに処理を実装してください
}

// テスト用
handleResult({ success: true, data: "Data loaded" });
handleResult({ success: false, error: "Network error" });
npx tsc practice5_1.ts && node practice5_1.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のpractice5_1.tsに書かれている内容を実行します。
出力されたファイル(編集不可):practice5_1.js

練習問題2: 図形の面積計算

Circle 型と Square 型を定義し、それらのUnion型である Shape を定義してください。

  • Circle は kind: 'circle' と radius: number を持ちます。
  • Square は kind: 'square' と sideLength: number を持ちます。
  • getArea 関数で、渡された図形に応じて面積を計算して返してください(円周率は Math.PI を使用)。
ファイルを編集:practice5_2.ts
// ここに型を定義

function getArea(shape: Shape): number {
  // ここに実装 (switch文やif文で kind プロパティによる絞り込みを行う)
  return 0;
}

// テスト用
console.log(getArea({ kind: 'circle', radius: 10 }));
console.log(getArea({ kind: 'square', sideLength: 5 }));
npx tsc practice5_2.ts && node practice5_2.js
ブラウザ上で動作するTypeScriptの実行環境です。
左上の実行ボタンを押して、このページ内のpractice5_2.tsに書かれている内容を実行します。
出力されたファイル(編集不可):practice5_2.js
前のページ« 関数の型定義
次のページジェネリクス »