TypeScriptは、大規模なウェブ開発の業界標準になりました。ほとんどの開発者はインターフェースと型の基本を知っていますが、本当の力はその高度な型システムにあります。ここでは、シニアエンジニアとしてあなたを際立たせる5つのパターンを紹介します。
1. ジェネリック制約 (Generic Constraints)
ジェネリクスは強力ですが、渡すことができるものを制限する必要がある場合があります。ここでは extends が役立ちます。
interface HasId { id: string; } function getById<T extends HasId>(list: T[], id: string): T | undefined { return list.find((item) => item.id === id); }
T が HasId を拡張することを保証することで、関数内での .id へのアクセスが安全であることを保証します。
2. 条件付き型 (Conditional Types)
条件付き型を使用すると、不均一な型マッピングを作成できます。構文はJavaScriptの三項演算子に似ています。
type IsString<T> = T extends string ? true : false; type A = IsString<string>; // true type B = IsString<number>; // false
実用的なユースケースは、共用体から型を除外することです。
type Diff<T, U> = T extends U ? never : T; type NonNullable<T> = Diff<T, null | undefined>;
3. マップ型 (Mapped Types)
マップ型を使用すると、プロパティを変換することで、古い型に基づいて新しい型を作成できます。
type ReadOnly<T> = { readonly [P in keyof T]: T[P]; }; interface User { name: string; age: number; } type ReadOnlyUser = ReadOnly<User>;
修飾子を追加または削除することもできます。
type Mutable<T> = { -readonly [P in keyof T]: T[P]; };
4. テンプレートリテラル型 (Template Literal Types)
TypeScript 4.1で導入されたこれらは、文字列型を直接操作することを可能にします。
type World = 'world'; type Greeting = `hello ${World}`; // "hello world" type Color = 'red' | 'blue'; type Quantity = 'light' | 'dark'; type Palette = `${Quantity}-${Color}`; // "light-red" | "light-blue" | "dark-red" | "dark-blue"
これは、CSSクラスやイベント名など、特定のパターンに従う文字列を入力するのに非常に便利です。
5. infer キーワード
条件付き型内の infer キーワードを使用すると、他の型から型を抽出できます。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; function check(): boolean { return true; } type CheckReturn = ReturnType<typeof check>; // boolean
ここでは、TypeScriptに関数の戻り値の型 R を「推論」して返すように求めています。
結論
これらのパターンを習得すると、堅牢で優れた開発者エクスペリエンス(DX)を提供するライブラリとユーティリティを作成できます。高度なTypeScriptの目標は、複雑さのための複雑さではなく、安全性と表現力です。