404 Not Found

404 Not Found


nginx

TypeScript のユニオン型とリテラル型

ユニオン型とリテラル型は、TypeScriptがJavaScriptを凌駕する第一歩です。これらを用いることで、「この値はAかBのいずれかである」ことや、「この値はこれらの選択肢のうちの1つに限られる」ことを表現できるようになります。

1. ユニオン型

ユニオン型は | を使用して複数の型を組み合わせ、その値が「これらの型のいずれかである」ことを示します:

(1) 基本的な構文

TYPESCRIPT
let id: number | string;

id = 42;        // ✅ number Legal
id = "ABC";     // ✅ string Legal
id = true;      // ❌ boolean Not in a composite type

(2) 一般的な用途:関数の引数

ユニオン型の最も一般的な用途は、関数がさまざまな型の引数を受け取れるようにすることです:

TYPESCRIPT
function printId(id: number | string) {
  console.log("YourID: :" + id);
}

printId(42);       // ✅
printId("ABC");    // ✅
printId(true);     // ❌

(3) ユニオン型の制限

union型の変数は、すべての型に共通するメンバにのみアクセスできます:

TYPESCRIPT
function process(value: number | string) {
  // value.toString()   // ✅ number and string All of them toString
  // value.toUpperCase() // ❌ number None toUpperCase
  // value.toFixed(2)    // ❌ string None toFixed
}
📌 理由: TypeScript は、value がユニオンのどの要素であっても、コードの安全性が保たれるようにする必要があります。すべての要素に共通するプロパティやメソッドのみを直接呼び出すことができます。特定の型の要素にアクセスするには、まず「型の絞り込み」を行う必要があります(第3節を参照)。


2. リテラル型

リテラル型は、変数の値を特定のリテラルに制限します。つまり、「任意の文字列」ではなく、「これらの特定の文字列のみ」となります。

(1) 3種類のリテラル

リテラル型 構文
文字列リテラル "value1" | "value2" "north" | "south" | "east" | "west"
数値リテラル 1 | 2 | 3 0 | 1 | 2
ブールリテラル true | false boolean と実際に等しい(値は2つだけ)

(2) 文字列リテラル型

TYPESCRIPT
let direction: "north" | "south" | "east" | "west";

direction = "north";    // ✅
direction = "up";       // ❌ "up" Not in a composite type

(3) 数値リテラル型

TYPESCRIPT
type HttpStatusCode = 200 | 301 | 404 | 500;

let code: HttpStatusCode = 200;   // ✅
let code2: HttpStatusCode = 201;  // ❌ 201 Not in a composite type

(4) ブールリテラル型

TYPESCRIPT
type YesNo = true | false;  // equivalent to boolean
type StrictTrue = true;     // It can only be true
💡 ヒント: ブールリテラル型はそれ自体ではあまり意味を持ちませんが(true | false は単なるブール値です)、ユニオン型で他の型と組み合わせると便利です。例えば、string | true は「文字列または true」を表します。

▶ 例:リテラル型を使用したロールの権限の定義

TYPESCRIPT
type Role = "admin" | "editor" | "viewer";

function checkPermission(role: Role) {
  if (role === "admin") {
    console.log("Administrator:Full Access");
  } else if (role === "editor") {
    console.log("Editor:Editable Content");
  } else {
    console.log("Viewers:Read-only access");
  }
}

checkPermission("admin");   // ✅
checkPermission("editor");  // ✅
checkPermission("guest");   // ❌ Compilation Error——"guest" Not legal Role

出力:

TEXT
Administrator:Full Access
Editor:Editable Content

3. 型絞り込み(Type Narrowing)

union型の変数は、特定の型のメンバに直接アクセスすることはできませんが、「型絞り込み」によってスコープを絞り込むことができます。

(1) typeofによる型絞り込み

TYPESCRIPT
function process(value: number | string) {
  if (typeof value === "string") {
    // In this branch,TypeScript knows value is string
    console.log(value.toUpperCase());  // ✅ string Methods
  } else {
    // In this branch,TypeScript knows value is number
    console.log(value.toFixed(2));     // ✅ number Methods
  }
}

(2) 平等の範囲の狭窄

TYPESCRIPT
function compare(a: string | number, b: string | boolean) {
  if (a === b) {
    // a and b equal,Their intersection type is string
    console.log(a.toUpperCase());  // ✅ Here a It must be string
  }
}

(3) in 演算子の範囲の絞り込み

TYPESCRIPT
function process(input: { name: string } | { age: number }) {
  if ("name" in input) {
    console.log(input.name);  // ✅ Has name property,Inferred as { name: string }
  } else {
    console.log(input.age);   // ✅ None name,Inferred as { age: number }
  }
}

(4) instanceof による型絞り込み

TYPESCRIPT
function processDate(value: Date | string) {
  if (value instanceof Date) {
    console.log(value.toISOString());  // ✅ Date Methods
  } else {
    console.log(value.toUpperCase());  // ✅ string Methods
  }
}

▶ 例:型絞り込みの完全な実例

TYPESCRIPT
function formatValue(value: number | string | boolean): string {
  if (typeof value === "number") {
    return "Numbers:" + value.toFixed(2);
  } else if (typeof value === "string") {
    return "String:" + value.toUpperCase();
  } else {
    return "Boolean:" + value;
  }
}

console.log(formatValue(3.14159));
console.log(formatValue("hello"));
console.log(formatValue(true));

出力:

TEXT
Numbers:3.14
String:HELLO
Boolean:true

4. ユニオン型およびリテラル型のための古典的なパターン

ユニオン型とリテラル型を組み合わせることで、非常に強力な型制約を実現できます。以下に、3つの典型的なパターンを挙げます。

(1) パターン 1:区別された和集合

同じプロパティに対して異なるリテラル値を使用することで、ユニオンのメンバーを区別します:

TYPESCRIPT
interface Circle {
  kind: "circle";       // Identifiable Attributes
  radius: number;
}

interface Rectangle {
  kind: "rectangle";    // Identifiable Attributes
  width: number;
  height: number;
}

type Shape = Circle | Rectangle;

function getArea(shape: Shape): number {
  if (shape.kind === "circle") {
    return Math.PI * shape.radius ** 2;   // ✅ Accessible radius
  } else {
    return shape.width * shape.height;     // ✅ Accessible width、height
  }
}
📌 ポイント: 各インターフェースには kind プロパティがありますが、その値はそれぞれ異なるリテラル型です。TypeScript は kind の値を使用して型を絞り込み、そのインターフェース固有のプロパティに安全にアクセスします。

(2) パターン 2:オプションの値 + 未定義

TYPESCRIPT
type Result = string | undefined;

function search(query: string): Result {
  if (query.length === 0) return undefined;
  return "Found:" + query;
}

let result = search("TypeScript");
if (result !== undefined) {
  console.log(result.toUpperCase());  // ✅ narrowed to string
}

(3) パターン 3:ステートマシン

TYPESCRIPT
type RequestStatus = "idle" | "loading" | "success" | "error";

interface RequestState {
  status: RequestStatus;
  data?: string;
  error?: string;
}

function renderState(state: RequestState): string {
  switch (state.status) {
    case "idle":
      return "Waiting......";
    case "loading":
      return "Loading......";
    case "success":
      return "Success:" + state.data;    // ✅ success in that state data Existence
    case "error":
      return "Error:" + state.error;   // ✅ error in that state error Existence
  }
}

5. never 型と網羅的なチェック

TypeScript が「あり得ないシナリオ」に絞り込まれた場合、型は never になります:

TYPESCRIPT
type Shape = "circle" | "square";

function getIcon(shape: Shape): string {
  switch (shape) {
    case "circle": return "⭕";
    case "square": return "⬜";
    default:
      // If all case It's all taken care of.,shape Here, the type is never
      const _exhaustiveCheck: never = shape;  // ✅ If omitted case,An error will occur here
      return _exhaustiveCheck;
  }
}
💡 ヒント: never の網羅的なチェックパターン――switch ステートメントの default 分岐内で、never 型の変数に値を代入する。今後、Shapeに新しいメンバーを追加した際、対応するcaseを追加し忘れた場合、TypeScriptはdefault分岐でエラーを発生させ、追加を促します。

▶ 例:網羅的チェックの実用的な効果

TYPESCRIPT
type TrafficLight = "red" | "yellow" | "green";

function getAction(light: TrafficLight): string {
  switch (light) {
    case "red": return "Stop";
    case "yellow": return "Note";
    // Intentional omission "green" 's case
    default:
      // If you add the next line,TypeScript It will throw an error:
      // You cannot convert the type "green" Assignment to a Type "never"
      const exhaustive: never = light;
      return "Unknown";
  }
}

❓ よくある質問

Q 和集合型と積集合型の違いは何ですか?
A 和集合型 (A | B) は「A または B」を意味します。これは和集合をとるため、値はどちらか一方を満たせば十分です。一方、積集合型 (A & B) は「A と B の両方」を意味します。これは積集合をとるため、値は両方を満たす必要があります。第20課では、積集合型について詳しく説明します。
Q リテラル型と列挙型、どちらを使うべきですか?
A ユニオンリテラル型を推奨します。列挙型よりも軽量(コンパイル時に余分なコードが生成されない)であり、JavaScriptのネイティブ文字列や数値と完全に互換性があります。列挙型は、逆マッピング(値 → 名前)が必要な場合や、実行時にすべてのメンバーを反復処理する必要がある場合に適しています。第12課では、この2つを比較します。
Q typeof はすべての型を検出できますか?
A いいえ。typeof が識別できるのは、「number」、「string」、「boolean」、「symbol」、「bigint」、「object」、「function」、および「undefined」の型のみです。nulltypeof nullは「object」を返します)などの参照型、配列、およびDateについては、instanceofやその他の方法を使用して型を絞り込む必要があります。詳細な説明については、第17課を参照してください。
Q never 型はどのような場合に使用されますか?
A never 型は主に次の 2 つの場面で現れます:(1) 型が不可能な分岐に絞り込まれたときに自動的に現れる場合、および (2) 関数が決して値を返さない場合(例外がスローされたり、無限ループが発生したりする場合など)。初心者は、「網羅的チェック」というパターンさえ理解しておけば十分です。これは、switchdefault節でneverを使用し、欠落しているcaseがないかを確認するものです。

📖 まとめ

📝 練習問題

  1. 基本問題(難易度 ⭐):ユニオン型 Status = "active" | "inactive" | "banned" を定義し、それに対応する中国語の説明を返す関数 getStatusText(status: Status) を作成してください。
  2. 上級問題(難易度 ⭐⭐):区別可能な和集合型 Result = SuccessResult | ErrorResult を定義せよ。ここで、SuccessResultsuccess: truedata: string からなり、ErrorResultsuccess: falseerror: string からなるものとする。Result を処理し、success, safely accesses either data or error の値に基づいて処理を行う関数を記述せよ。
  3. チャレンジ問題(難易度 ⭐⭐⭐):switch文で7日間すべてを処理するために、網羅的チェックを用いた関数 describeDay(day: "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun") を作成してください。その後、意図的に1日を省略し、「決して起こらない」はずの網羅的チェックによって生成されるエラーメッセージを確認してください。
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%