TypeScript意外と忘れがちな機能
こんにちは。FEチームのMapleです。私たちのチームは、現在のシステムアーキテクチャを見直し、Reactを用いた新しいアーキテクチャへの移行を検討しています。今回は先日TypeScriptの型について解説を行ったので、意外と忘れがちな機能について解説出来たらなと思います。
はじめに
- 私が思った意外と忘れがちな機能なので、人によるかもしれません
- 今回はコードを長めに実際に導入されそうな感じで記述出来たらなと思います
Conditional Typesの応用
TypeScriptの条件付き型(Conditional Types)は、型を柔軟に操作する強力なツールです。T extends U ? X : Y
の形式で、条件に応じた型を返すことができます。
Conditional Typesの例
この例では、FetchStatus型が、FetchResponseにerrorプロパティが存在するかどうかによって、"failed"か"success"を返します。
type FetchStatus<T> = T extends { error: Error } ? "failed" : "success";
interface FetchResponse {
data: string;
error?: Error;
}
type Status = FetchStatus<FetchResponse>; // "success" または "failed"
Template Literal Typesの威力
テンプレートリテラル型を使うことで、文字列操作を型レベルで行えます。
Template Literal Typesの例
この例では、welcome_enやwelcome_jaのように、指定されたロケールIDに基づいたメッセージIDを扱うことができます。
type LocaleIDs = "en" | "ja" | "fr";
type LocaleMessageIDs = `welcome_${LocaleIDs}`;
const welcomeMessage: LocaleMessageIDs = "welcome_en"; // 正しい
const invalidMessage: LocaleMessageIDs = "welcome_de"; // エラー: "welcome_de"は型に適合しません
Mapped Typesで動的に型を作成
Mapped Typesを使うと、既存の型を元に新しい型を作成できます。
Mapped Typesの例
この例では、すべてのプロパティがオプショナルなOptionalTodo型を作成しました。
全部に?を付けているコードよく見ますよね
interface Todo {
title: string;
description: string;
completed: boolean;
}
type OptionalTodo = Partial<Todo>; // すべてのプロパティがオプショナルになる
const todo: OptionalTodo = {
title: "Learn TypeScript"
}
Lookup Typesを使った型の絞り込み
Lookup Typesを使うと、オブジェクト型の特定のプロパティの型を取得できます。
複雑な型の一部を再利用したり、絞り込んだりすることができます。
Lookup Typesを使った型の絞り込みの例
この例では、User型のpreferencesプロパティのthemeの型を抽出し、UserTheme型として利用しています。
interface User {
id: number;
name: string;
preferences: {
theme: "light" | "dark";
notifications: boolean;
};
}
type UserTheme = User['preferences']['theme']; // "light" | "dark
UnionsとIntersectionsの使い方
Union型とIntersection型を効果的に組み合わせることで、より良い型システムを構築できます。
UnionsとIntersectionsの例
この例では、ApiResponse型がErrorResponseとDataResponseのいずれかで、レスポンスがどちらの型かによって処理を分岐させています。
interface ErrorResponse {
error: string;
}
interface DataResponse {
data: string;
}
type ApiResponse = ErrorResponse | DataResponse;
function handleResponse(response: ApiResponse) {
if ('error' in response) {
console.error(`Error: ${response.error}`);
} else {
console.log(`Data: ${response.data}`);
}
まとめ
- 意外と忘れがちな機能がありますが、キャッチアップしつつプロダクトに導入出来たらなとおもいます。
- 今度はもっとより詳しく型を解説出来たらなと思います。
株式会社SODAの開発組織がお届けするZenn Publicationです。 是非Entrance Bookもご覧ください! → recruit.soda-inc.jp/engineer
Discussion