TypeScript - マップ型:初学者向けガイド
こんにちは、未来のTypeScript魔法使いさんたち!今日は、マップ型の世界に興味深く飛び込んでみましょう。プログラミングが初めての方でも心配しないでください。私はあなたの親切なガイドとして、ステップバイステップで進めていきます。このチュートリアルの終わりまでに、プロのように型をマッピングできるようになるでしょう!
マップ型とは?
まず、マップ型とは何かを理解しましょう。箱の中に色々なチョコレートが入っているとします。そして、それぞれのチョコレートを金の包装紙で包む新しい箱を作りたいとします。これがTypeScriptにおけるマップ型の仕事です。既存の型を基にして、一定のルールに基づいて新しい型を生成します。
ビルトインマップ型
TypeScriptには、非常に便利ないくつかの定義済みマップ型があります。一つずつ見ていきましょう。
1. Partial
Partial<T>
型は、T
のすべてのプロパティをオプションにします。厳しいレシピを柔軟なものに変えるようなものです。
interface Recipe {
name: string;
ingredients: string[];
cookingTime: number;
}
type FlexibleRecipe = Partial<Recipe>;
// すべてのプロパティを指定しなくても良い
const quickSnack: FlexibleRecipe = {
name: " Toast",
// ingredientsとcookingTimeは省略可
};
この例では、FlexibleRecipe
を使うことで、すべてのプロパティを指定しなくても良いです。オブジェクトの一部を更新したいときに非常に便利です。
2. Required
Required<T>
型は、Partial<T>
の逆で、元の型でオプションだったプロパティも必須にします。
interface UserProfile {
name: string;
age?: number;
email?: string;
}
type CompleteUserProfile = Required<UserProfile>;
// すべてのプロパティを提供する必要があります
const user: CompleteUserProfile = {
name: "Alice",
age: 30,
email: "[email protected]"
};
ここで、CompleteUserProfile
は、元のUserProfile
でオプションだったage
とemail
も含めてすべてのプロパティを提供する必要があります。
3. Readonly
Readonly<T>
型は、T
のすべてのプロパティをリードオンリーにします。オブジェクトをガラスケースに入れるようなものです。見ることはできますが、触ることはできません。
interface Toy {
name: string;
price: number;
}
type CollectibleToy = Readonly<Toy>;
const actionFigure: CollectibleToy = {
name: "Superhero",
price: 19.99
};
// 以下はエラー becomes
// actionFigure.price = 29.99;
この例では、一度actionFigure
を作成すると、プロパティを変更することができません。不変オブジェクトを作成するのに非常に便利です。
4. Pick<T, K>
Pick<T, K>
型は、T
から指定されたプロパティK
だけを選択して新しい型を作成します。お気に入りの機能を選別するようなものです。
interface Smartphone {
brand: string;
model: string;
year: number;
color: string;
price: number;
}
type BasicPhoneInfo = Pick<Smartphone, 'brand' | 'model'>;
const myPhone: BasicPhoneInfo = {
brand: "TechBrand",
model: "X2000"
};
ここで、BasicPhoneInfo
はSmartphone
のbrand
とmodel
プロパティだけを含み、他は除きます。
5. Omit<T, K>
Omit<T, K>
型は、Pick<T, K>
型の逆で、T
から指定されたプロパティK
を除いて新しい型を作成します。
interface Book {
title: string;
author: string;
pages: number;
isbn: string;
}
type BookPreview = Omit<Book, 'pages' | 'isbn'>;
const preview: BookPreview = {
title: "TypeScript Adventures",
author: "Code Wizard"
};
この場合、BookPreview
はBook
のすべてのプロパティを含みますが、pages
とisbn
を除きます。
マップ型の使用例
ビルトインマップ型を見てきたので、現実のシナリオでどのように使用できるかを見てみましょう。
例1: フォーム状態の作成
フォームを作成して、どのフィールドが編集されたかを追跡したいとします:
interface LoginForm {
username: string;
password: string;
rememberMe: boolean;
}
type FormTouched = { [K in keyof LoginForm]: boolean };
const touchedFields: FormTouched = {
username: true,
password: false,
rememberMe: true
};
ここで、FormTouched
型はLoginForm
と同じキーを持っていますが、すべての値がブール型で、フィールドがタッチされたかどうかを示します。
例2: API レスポンスラッパー
APIが異なるデータ型を返す場合、それぞれのレスポンスを標準的な形式でラップしたいとします:
interface ApiResponse<T> {
data: T;
status: 'success' | 'error';
timestamp: number;
}
type UserData = { id: number; name: string; email: string };
type ProductData = { id: number; name: string; price: number };
const userResponse: ApiResponse<UserData> = {
data: { id: 1, name: "John Doe", email: "[email protected]" },
status: 'success',
timestamp: Date.now()
};
const productResponse: ApiResponse<ProductData> = {
data: { id: 101, name: "Laptop", price: 999.99 },
status: 'success',
timestamp: Date.now()
};
この例では、ジェネリックを使用して、柔軟で再利用可能な型構造を作成しています。
カスタムマップ型の作成
さあ、TypeScriptの力を試して、カスタムマップ型を作成しましょう!
カスタム型1: Nullable
すべてのプロパティをnullにできる型を作成しましょう:
type Nullable<T> = { [K in keyof T]: T[K] | null };
interface Person {
name: string;
age: number;
}
type NullablePerson = Nullable<Person>;
const maybePerson: NullablePerson = {
name: "Jane",
age: null // これは現在有効です
};
私たちのNullable<T>
型は、すべてのプロパティが元の型またはnull
のいずれかを持つことができます。
カスタム型2: Freezable
オブジェクトにfreeze
メソッドを追加する型を作成しましょう:
type Freezable<T> = T & { freeze(): Readonly<T> };
interface Config {
theme: string;
fontSize: number;
}
function makeFreezable<T>(obj: T): Freezable<T> {
return {
...obj,
freeze() {
return Object.freeze({ ...this }) as Readonly<T>;
}
};
}
const config = makeFreezable<Config>({
theme: "dark",
fontSize: 14
});
const frozenConfig = config.freeze();
// frozenConfig.theme = "light"; // これはエラーを引き起こします
このカスタム型は、任意のオブジェクトにfreeze
メソッドを追加し、不変なバージョンを作成することができます。
結論
哇、今日は多くのことをカバーしました!ビルトインマップ型からカスタム型まで、TypeScriptがどれほど強力で柔軟であるかを感じていただけたでしょうか。マップ型は、TypeScriptのツールボックスにおける魔法の杖のような存在で、型を変換し、Manipulateすることが非常に便利な方法でできます。
マップ型をマスターする鍵は練習です。自分で作成してみたり、異なる組み合わせを試してみたりして、機能的で優雅で型安全なTypeScriptコードを書けるようになるまでががんばりましょう。
codingを続け、学び続け、そして最も重要なのは、TypeScriptを楽しみましょう!
Credits: Image by storyset