この記事は、 PLEX Advent Calendar 2024の5日目の記事です。
今回紹介する下記の型は、
よく使うもの、見かけた時にすぐに理解しづらいものを選んでいます。
リテラル型
特定の値そのものを型として使用できる機能
// 例1: type Direction = "north" | "south" | "east" | "west" let myDirection: Direction = "north" // OK myDirection = "up" // ❌ エラー: "up"は許可されていない // 例2: // HTTP メソッドを制限する type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" function request(url: string, method: HttpMethod) { // ... } request("/api/users", "GET") // OK request("/api/users", "PATCH") // ❌ エラー
ユニオン型( | )
複数の型を組み合わせて、型の選択肢を作る機能
// 1. 基本的なユニオン型 type StringOrNumber = string | number let value: StringOrNumber value = "hello" // OK value = 42 // OK value = true // ❌ エラー: booleanは許可されていない
型の交差( & )
全ての型の特徴を持つ新しい型を作る機能
type BasicInfo = { id: number // 数値型のID name: string // 文字列型の名前 } type PersonalUser = BasicInfo & { type: "personal" // リテラル型で "personal" という固定値 age: number // 数値型の年齢 } 使用例: const user: PersonalUser = { id: 1, name: "田中", type: "personal", age: 25 }
マップ型
既存の型を基に、新しい型を作成する機能
type GameSearchState = { gameId: number nameQuery: string isSoldOut: boolean } type UrlTypes<T> = { [K in keyof T as KebabCase<K>]: string }
- ジェネリック型(
<T>
)を使用 - マップ型(
[K in keyof T]
)で型のキーをイテレート as KebabCase<K>
でキーをケバブケース(ハイフン区切り)に変換- 全ての値の型を
string
に設定
// UrlTypes<GameSearchState> { "game-id": string, "name-query": string, "is-sold-out": string }
条件付き型 (T extends U ? X : Y)
条件に応じた型の分岐
[K in keyof T as T[K] extends number ? K : never]: T[K]
K in keyof T
- 型Tのすべてのキーをイテレートas T[K] extends number ? K : never
- 条件付き型で、値の型に基づいてキーをフィルタリング: T[K]
- マッピングされた各キーの値の型を元の型と同じに この型は「数値型のプロパティのみを抽出する」という動作をする
type Example = { id: number name: string age: number isActive: boolean } type NumberPropertiesOnly = { [K in keyof Example as Example[K] extends number ? K : never]: Example[K] } // 結果として生成される型: // { // id: number // age: number // }
ReturnType
組み込みユーティリティ型の1つ
関数の戻り値の型を抽出する際に使用される
// 1. 基本的な関数の例 function getMessage(): string { return "Hello" } type MessageType = ReturnType<typeof getMessage> // MessageType は string // 2. 複雑な戻り値を持つ関数 function fetchUser() { return { id: 1, name: "田中", age: 25 } } type User = ReturnType<typeof fetchUser> // User は { // id: number // name: string // age: number // }
Parameters
組み込みユーティリティ型の1つ
関数の引数の型をタプル型として抽出
// 1. 基本的な関数の例 function greet(name: string, age: number) { return `Hello, ${name}! You are ${age} years old.` } type GreetParams = Parameters<typeof greet> // GreetParams は [string, number] // パラメータを個別に取得することも可能 type FirstParam = Parameters<typeof greet>[0] // string type SecondParam = Parameters<typeof greet>[1] // number // 2. オブジェクトパラメータを持つ関数 function createUser(params: { name: string age: number email: string }) { return params } type CreateUserParams = Parameters<typeof createUser>[0] // CreateUserParams は { // name: string // age: number // email: string // }
as const, satisfies
const localizeData = { novel: { chapter: "チャプター", episode: "話", }, } as const satisfies { novel: { chapter: string episode: string } }
as const
の役割:
1. 全てのプロパティを読み取り専用(readonly)にする
2. リテラル型として扱われるようになる
3. "チャプター"
はstring
型ではなく"チャプター"
というリテラル型
satisfies
の役割:
1. オブジェクトが特定の型を満たすことを検証
2. 型の検証と推論の両方の利点を得られる
3. エラーを早期に発見できる
// ✅ OK - 型チェックが通る const chapter = localizeData.novel.chapter // 型は "チャプター" (リテラル型) // ❌ エラー - 読み取り専用なので変更不可 localizeData.novel.chapter = "章" // ✅ OK - 型チェックによる補完が効く const hasChapter = "chapter" in localizeData.novel
この構文の利点:
- 型安全性:
- オブジェクトの構造が指定した型と一致することを保証
- 必要なプロパティの欠落を防ぐ
- リテラル型の保持:
as const
により、具体的な文字列値が型として保持される- より厳密な型チェックが可能
- IDE支援:
- 優れたコード補完
- リファクタリング時の安全性
- 実行時の不変性:
- オブジェクトとその中身が読み取り専用になる
参考元:
値・型・変数 | TypeScript入門『サバイバルTypeScript』
TypeScript特有の組み込み型関数 - log.pocka.io