- Day 17:Union Typeで「ユーザー権限」を型として表現する
- Union Typeとは:値の「候補」を型で表す
- Literal Typeとは:具体的な「値」を型にする
- ユーザー権限を型で表現する:Role型を作る
- Role型をUser型に組み込む
- 権限によって動作を変える:Union Typeを使った分岐
- ユーザー権限チェック関数を作る
- Day 17 練習テンプレート:ユーザー権限を型で表現する
- Day 17のまとめ
- Day 17:Union Typeで「世界のルール」を型にしてみる
- Union TypeとLiteral Typeの基本をおさらいする
- RoleをUnion Typeにする(ユーザー権限)
- StatusをUnion Typeにする(状態・ステータス)
- GenderをUnion Typeにする(性別の表現)
- PaymentMethodをUnion Typeにする(支払い方法)
- PriorityをUnion Typeにする(優先度)
- 5つのUnion Typeをまとめて使ってみる
- Day 17 演習テンプレート:5種類のUnion Type
- Day 17のまとめ
Day 17:Union Typeで「ユーザー権限」を型として表現する
第3週は、TypeScriptの核心である「型」をじっくり育てていく週です。 Day 17のテーマは Union Type と Literal Type。 今日は、これらを使って「ユーザー権限(admin / user / guest)」を型で表現していきます。
Union Typeとは:値の「候補」を型で表す
「AかBかCか」を型で書ける
Union Typeは、ざっくり言うと 「この値はAかBかCのどれかです」と型で宣言する仕組みです。
記号は |(パイプ)を使います。
// 数値か文字列のどちらか
type NumberOrString = number | string;
let value: NumberOrString;
value = 123; // OK(number)
value = "hello"; // OK(string)
// value = true; // NG(booleanは許可していない)
TypeScriptnumber | stringは、「numberかstringのどちらか」という意味です。- Union Typeを使うと、「許可する型の候補」をはっきり書けるようになります。
Literal Typeとは:具体的な「値」を型にする
「この3つの文字列だけOK」を型で表現する
Literal Typeは、具体的な値そのものを型として扱う考え方です。
// "yes" か "no" のどちらかだけを許可する型
type YesNo = "yes" | "no";
let answer: YesNo;
answer = "yes"; // OK
answer = "no"; // OK
// answer = "maybe"; // NG(定義していない文字列)
TypeScript"yes"や"no"のような「文字列リテラル」をそのまま型として使っています。- Union Typeと組み合わせることで、「この文字列の候補だけOK」という型を作れます。
この仕組みを使うと、「ユーザー権限は admin / user / guest の3種類だけ」というルールを、型として表現できます。
ユーザー権限を型で表現する:Role型を作る
権限の候補をLiteral Type + Union Typeで定義する
まずは、ユーザー権限を表す Role 型を作ります。
// ユーザー権限を表す型
type Role = "admin" | "user" | "guest";
TypeScriptRoleは、「adminかuserかguestのどれか」という意味の型です。- これにより、「権限としてありえる値」を型レベルで制限できます。
// Role型を使った変数
let role1: Role;
role1 = "admin"; // OK
role1 = "user"; // OK
role1 = "guest"; // OK
// role1 = "superuser"; // NG:定義していない権限
TypeScript重要ポイント(ここはしっかり押さえたいところです):
- 文字列を自由に書けるようにしてしまうと、
"admni"のようなタイプミスも通ってしまいます。 - Literal Type + Union Typeを使うことで、「この3つ以外は許可しない」というルールを型で表現できます。
- これは、権限やステータスなど「限られた候補しかない値」を扱うときに、とても強力なパターンです。
Role型をUser型に組み込む
ユーザー情報に権限を持たせる
次に、Role 型を User 型に組み込んでみます。
// ユーザー権限型
type Role = "admin" | "user" | "guest";
// ユーザーを表す型
type User = {
id: number; // ユーザーID
name: string; // 名前
email: string; // メールアドレス
role: Role; // 権限(Role型を再利用)
};
// User型を使った例
const adminUser: User = {
id: 1,
name: "Admin Taro",
email: "[email protected]",
role: "admin",
};
const normalUser: User = {
id: 2,
name: "User Hanako",
email: "[email protected]",
role: "user",
};
const guestUser: User = {
id: 3,
name: "Guest Jiro",
email: "[email protected]",
role: "guest",
};
TypeScriptポイント:
role: Role;と書くことで、「ユーザーの権限は必ずadmin/user/guestのどれか」というルールになります。- もし
role: "superadmin"のような値を入れようとすると、コンパイル時にエラーになります。
権限によって動作を変える:Union Typeを使った分岐
Roleに応じてメッセージを変える関数
Union Typeは、「値の候補が限られている」ことがわかっているので、 switch 文などで分岐するときにも、とても相性がよいです。
// 権限に応じてメッセージを返す関数
function getRoleMessage(role: Role): string {
switch (role) {
case "admin":
return "管理者権限です。すべての操作が可能です。";
case "user":
return "一般ユーザー権限です。通常の操作が可能です。";
case "guest":
return "ゲスト権限です。閲覧のみ可能です。";
// default は不要(Roleは3つに限定されているため)
}
}
// テスト
console.log(getRoleMessage("admin"));
console.log(getRoleMessage("user"));
console.log(getRoleMessage("guest"));
TypeScript深掘りポイント:
Roleが"admin" | "user" | "guest"に限定されているため、switchのケースも3つだけで済みます。- TypeScriptは、「すべての候補を網羅しているか」をチェックしてくれるので、抜け漏れが減ります。
- もし新しい権限
"superadmin"を追加したら、Role型とswitchの両方を更新することで、コード全体の整合性を保てます。
ユーザー権限チェック関数を作る
adminかどうかを判定する関数
Union Typeを使った権限チェックの例として、「adminかどうか」を判定する関数を作ってみます。
// admin権限かどうかを判定する関数
function isAdmin(user: User): boolean {
return user.role === "admin";
}
// テスト
console.log(isAdmin(adminUser)); // true
console.log(isAdmin(normalUser)); // false
console.log(isAdmin(guestUser)); // false
TypeScriptguestかどうかを判定する関数
// guest権限かどうかを判定する関数
function isGuest(user: User): boolean {
return user.role === "guest";
}
console.log(isGuest(adminUser)); // false
console.log(isGuest(guestUser)); // true
TypeScriptポイント:
user.roleの型がRoleなので、比較対象も"admin"/"user"/"guest"の3つに自然と絞られます。- 「ありえない権限」を比較してしまうミスを防げるのが、Literal Type + Union Typeの強みです。
Day 17 練習テンプレート:ユーザー権限を型で表現する
最後に、今日の内容をひとつのファイルにまとめた練習テンプレートを載せます。 このままコピーして、権限の種類を増やしたり、権限ごとの機能制限を追加したりしながら、自分なりの「権限設計」を試してみてください。
// day17-union-role.ts
// Day 17:Union Typeでユーザー権限を型で表現する
// ユーザー権限を表すLiteral + Union Type
type Role = "admin" | "user" | "guest";
// ユーザー型
type User = {
id: number;
name: string;
email: string;
role: Role;
};
// ユーザー権限に応じたメッセージを返す関数
function getRoleMessage(role: Role): string {
switch (role) {
case "admin":
return "管理者権限です。すべての操作が可能です。";
case "user":
return "一般ユーザー権限です。通常の操作が可能です。";
case "guest":
return "ゲスト権限です。閲覧のみ可能です。";
}
}
// admin判定
function isAdmin(user: User): boolean {
return user.role === "admin";
}
// guest判定
function isGuest(user: User): boolean {
return user.role === "guest";
}
// テストユーザー
const adminUser: User = {
id: 1,
name: "Admin Taro",
email: "[email protected]",
role: "admin",
};
const normalUser: User = {
id: 2,
name: "User Hanako",
email: "[email protected]",
role: "user",
};
const guestUser: User = {
id: 3,
name: "Guest Jiro",
email: "[email protected]",
role: "guest",
};
// テスト出力
console.log(adminUser.name, ":", getRoleMessage(adminUser.role), "admin?", isAdmin(adminUser));
console.log(normalUser.name, ":", getRoleMessage(normalUser.role), "admin?", isAdmin(normalUser));
console.log(guestUser.name, ":", getRoleMessage(guestUser.role), "guest?", isGuest(guestUser));
TypeScriptDay 17のまとめ
Day 17では、
|を使った Union Type で「AかBかCか」という型を表現する方法- 具体的な文字列を型にする Literal Type を使って、「権限の候補を限定する」考え方
Role = "admin" | "user" | "guest"という型で、ユーザー権限を安全に表現するパターンUser型にrole: Roleを組み込み、権限に応じてメッセージや動作を変える関数を作る流れ
を、具体的なコードとともに体験しました。
Union TypeとLiteral Typeは、「ありえる値の範囲」を型でしっかり絞り込むための強力な道具です。 ぜひ、ステータス("draft" | "published" | "archived")や支払い方法("card" | "bank" | "cash")など、身近な例でも試してみてください。 型で「世界のルール」を表現できるようになると、コードの安全性と読みやすさがぐっと上がっていきます。
Day 17:Union Typeで「世界のルール」を型にしてみる
第3週は、TypeScriptの核心である「型」をじっくり育てていく週です。 Day 17の演習テーマは、Union Type と Literal Type を使って、よくある「分類・ステータス」を型で表現することです。
今回Union Typeにするのは次の5つです。
- Role
- Status
- Gender
- PaymentMethod
- Priority
ひとつひとつ、初心者の方にもイメージしやすいように、ステップバイステップで作っていきます。
Union TypeとLiteral Typeの基本をおさらいする
Union Typeとは
Union Typeは、ざっくり言うと 「この値はAかBかCのどれかです」と型で宣言する仕組みです。 記号は |(パイプ)を使います。
// 数値か文字列のどちらか
type NumberOrString = number | string;
let value: NumberOrString;
value = 123; // OK(number)
value = "hello"; // OK(string)
// value = true; // NG(booleanは許可していない)
TypeScriptnumber | stringは、「numberかstringのどちらか」という意味です。- Union Typeを使うと、「許可する型の候補」をはっきり書けるようになります。
Literal Typeとは
Literal Typeは、具体的な値そのものを型として扱う考え方です。
// "yes" か "no" のどちらかだけを許可する型
type YesNo = "yes" | "no";
let answer: YesNo;
answer = "yes"; // OK
answer = "no"; // OK
// answer = "maybe"; // NG(定義していない文字列)
TypeScript"yes"や"no"のような「文字列リテラル」をそのまま型として使っています。- Union Typeと組み合わせることで、「この文字列の候補だけOK」という型を作れます。
この仕組みを使って、現実世界の「分類・ステータス」を型にしていきます。
RoleをUnion Typeにする(ユーザー権限)
Roleの設計
まずは、ユーザー権限を表す Role から始めます。 よくある権限として、次の3つを想定します。
adminuserguest
// ユーザー権限を表す型
type Role = "admin" | "user" | "guest";
// Role型を使った例
let role: Role;
role = "admin"; // OK
role = "user"; // OK
role = "guest"; // OK
// role = "superuser"; // NG:定義していない権限
TypeScript重要ポイント:
- 文字列を自由に書けるようにしてしまうと、
"admni"のようなタイプミスも通ってしまいます。 - Literal Type + Union Typeを使うことで、「この3つ以外は許可しない」というルールを型で表現できます。
- 権限やステータスなど「限られた候補しかない値」を扱うときに、とても強力なパターンです。
StatusをUnion Typeにする(状態・ステータス)
Statusの設計
次に、よくある「状態」を表す Status を作ります。 例えば、次の3つを想定します。
active(有効)inactive(無効)pending(保留)
// ステータスを表す型
type Status = "active" | "inactive" | "pending";
let status: Status;
status = "active"; // OK
status = "inactive"; // OK
status = "pending"; // OK
// status = "deleted"; // NG:定義していないステータス
TypeScriptポイント:
- StatusをUnion Typeにしておくと、「このオブジェクトは必ずこの3つのどれかの状態」という前提でコードを書けます。
- 例えば、画面表示やボタンの有効・無効をStatusに応じて切り替えるときに便利です。
GenderをUnion Typeにする(性別の表現)
Genderの設計
性別の表現は、システムによってさまざまですが、ここではシンプルに次の3つを想定します。
malefemaleother
// 性別を表す型
type Gender = "male" | "female" | "other";
let gender: Gender;
gender = "male"; // OK
gender = "female"; // OK
gender = "other"; // OK
// gender = "unknown"; // NG:定義していない値
TypeScript大事なポイント:
- Genderのようなセンシティブな情報は、現実の要件に合わせて慎重に設計する必要があります。
- ここでは学習用としてシンプルな3種類にしていますが、実際のサービスでは「未回答」や「自由入力」などの選択肢も検討されます。
- Union Typeは、「システムとしてどういう選択肢を用意するか」を型で明確にするための道具だと考えてください。
PaymentMethodをUnion Typeにする(支払い方法)
PaymentMethodの設計
次に、支払い方法を表す PaymentMethod を作ります。 よくある支払い方法として、次の4つを想定します。
card(クレジットカード)bank(銀行振込)cash(現金)wallet(電子ウォレットなど)
// 支払い方法を表す型
type PaymentMethod = "card" | "bank" | "cash" | "wallet";
let payment: PaymentMethod;
payment = "card"; // OK
payment = "bank"; // OK
payment = "cash"; // OK
payment = "wallet"; // OK
// payment = "crypto"; // NG:定義していない支払い方法
TypeScriptポイント:
- PaymentMethodをUnion Typeにしておくと、「このサービスはどの支払い方法を受け付けるか」が型として明確になります。
- 新しい支払い方法を追加するときは、
PaymentMethod型に候補を足すことで、関連するコードの見直しもしやすくなります。
PriorityをUnion Typeにする(優先度)
Priorityの設計
最後に、タスクやチケットなどでよく使う「優先度」を表す Priority を作ります。 ここでは、次の3つを想定します。
lowmediumhigh
// 優先度を表す型
type Priority = "low" | "medium" | "high";
let priority: Priority;
priority = "low"; // OK
priority = "medium"; // OK
priority = "high"; // OK
// priority = "urgent"; // NG:定義していない優先度
TypeScript深掘りポイント:
- PriorityをUnion Typeにしておくと、「優先度に応じて表示色を変える」「通知の強さを変える」といった処理が書きやすくなります。
- 例えば、
switch文で分岐するときも、3つのケースだけを考えればよくなり、抜け漏れが減ります。
5つのUnion Typeをまとめて使ってみる
練習用のUser型を作る
5つのUnion Typeを組み合わせて、練習用の User 型を作ってみます。
// 5つのUnion Type定義
type Role = "admin" | "user" | "guest";
type Status = "active" | "inactive" | "pending";
type Gender = "male" | "female" | "other";
type PaymentMethod = "card" | "bank" | "cash" | "wallet";
type Priority = "low" | "medium" | "high";
// ユーザー型(練習用)
type User = {
id: number;
name: string;
role: Role;
status: Status;
gender: Gender;
favoritePayment: PaymentMethod;
supportPriority: Priority;
};
// User型を使った例
const user1: User = {
id: 1,
name: "Taro",
role: "admin",
status: "active",
gender: "male",
favoritePayment: "card",
supportPriority: "high",
};
const user2: User = {
id: 2,
name: "Hanako",
role: "user",
status: "pending",
gender: "female",
favoritePayment: "cash",
supportPriority: "medium",
};
TypeScriptPriorityに応じてメッセージを変える関数
// 優先度に応じてメッセージを返す関数
function getPriorityMessage(priority: Priority): string {
switch (priority) {
case "low":
return "優先度は低めです。時間があるときに対応してください。";
case "medium":
return "通常の優先度です。なるべく早めに対応してください。";
case "high":
return "高い優先度です。できるだけすぐに対応してください。";
}
}
// テスト
console.log(user1.name, "のサポート優先度:", getPriorityMessage(user1.supportPriority));
console.log(user2.name, "のサポート優先度:", getPriorityMessage(user2.supportPriority));
TypeScriptDay 17 演習テンプレート:5種類のUnion Type
最後に、今日の内容をひとつのファイルにまとめた練習テンプレートを載せます。 このままコピーして、候補を増やしたり、関数を追加したりしながら、自分なりの「世界のルール」を型で表現してみてください。
// day17-union-practice.ts
// Day 17:5種類のUnion Type 演習テンプレート
// 1. Role(権限)
type Role = "admin" | "user" | "guest";
// 2. Status(状態)
type Status = "active" | "inactive" | "pending";
// 3. Gender(性別)
type Gender = "male" | "female" | "other";
// 4. PaymentMethod(支払い方法)
type PaymentMethod = "card" | "bank" | "cash" | "wallet";
// 5. Priority(優先度)
type Priority = "low" | "medium" | "high";
// 練習用User型
type User = {
id: number;
name: string;
role: Role;
status: Status;
gender: Gender;
favoritePayment: PaymentMethod;
supportPriority: Priority;
};
// 優先度メッセージ関数
function getPriorityMessage(priority: Priority): string {
switch (priority) {
case "low":
return "優先度は低めです。時間があるときに対応してください。";
case "medium":
return "通常の優先度です。なるべく早めに対応してください。";
case "high":
return "高い優先度です。できるだけすぐに対応してください。";
}
}
// テストユーザー
const user1: User = {
id: 1,
name: "Taro",
role: "admin",
status: "active",
gender: "male",
favoritePayment: "card",
supportPriority: "high",
};
const user2: User = {
id: 2,
name: "Hanako",
role: "user",
status: "pending",
gender: "female",
favoritePayment: "cash",
supportPriority: "medium",
};
console.log(user1.name, "のサポート優先度:", getPriorityMessage(user1.supportPriority));
console.log(user2.name, "のサポート優先度:", getPriorityMessage(user2.supportPriority));
TypeScriptDay 17のまとめ
Day 17では、
|を使った Union Type で「AかBかCか」という型を表現する方法- 具体的な文字列を型にする Literal Type を使って、「候補を限定する」考え方
Role/Status/Gender/PaymentMethod/Priorityの5つをUnion Typeとして設計する流れ- それらを組み合わせて
User型を作り、優先度に応じてメッセージを変える関数を書く練習
を、具体的なコードとともに体験しました。
Union TypeとLiteral Typeは、「ありえる値の範囲」を型でしっかり絞り込むための強力な道具です。 ぜひ、ステータスや権限、支払い方法など、身近な例でもどんどん試してみてください。 型で「世界のルール」を表現できるようになると、コードの安全性と読みやすさがぐっと上がっていきます。
