TypeScript:インターフェースの操作をもっと便利に!Pick、Omit、Excludeを活用した高度なテクニック
TypeScript インターフェースからキーを除外する方法
Pick<T, K> 型を利用する
Pick<T, K>
型は、T
型から K
型に指定されたプロパティのみを抽出した新しい型を定義します。この型を利用することで、除外したいキーを明確に指定することができます。
interface OriginalInterface {
id: number;
name: string;
age: number;
}
type RemovedAgeInterface = Pick<OriginalInterface, "id" | "name">; // 'age' プロパティを除外
利点
- 除外したいキーを明確に指定できる
- シンプルでわかりやすい構文
欠点
- 新しい型を定義する必要があるため、コードが煩雑になる場合がある
Omit<T, K>
型は、T
型から K
型に指定されたプロパティを除いた新しい型を定義します。Pick<T, K>
型とは異なり、除外するキーを羅列するのではなく、基底となる型から除外するキーを指定します。
interface OriginalInterface {
id: number;
name: string;
age: number;
}
type RemovedAgeInterface = Omit<OriginalInterface, "age">; // 'age' プロパティを除外
Pick<T, K>
型よりも簡潔に記述できる
ジェネリック型を利用する
ジェネリック型を利用することで、より柔軟性のあるキーの除外処理を行うことができます。例えば、除外するキーを条件式で判断したり、別の型から除外するキーを動的に取得したりすることができます。
type ExcludeKeys<T, K extends keyof T> = { [P in Exclude<keyof T, K>]: T[P] };
interface OriginalInterface {
id: number;
name: string;
age: number;
}
type ShouldExclude<P extends keyof OriginalInterface> = P extends "age" ? true : false;
type RemovedAgeInterface = ExcludeKeys<OriginalInterface, Extract<keyof OriginalInterface, ShouldExclude<keyof OriginalInterface>>>;
- 柔軟性のあるキーの除外処理が可能
- コードが複雑になる場合がある
型エイリアスを利用する
上記のいずれの方法でも、単純なキーの除外であれば、型エイリアスを利用して簡潔に記述することができます。
interface OriginalInterface {
id: number;
name: string;
age: number;
}
type RemovedAgeInterface = { id: OriginalInterface["id"]; name: OriginalInterface["name"]; }; // 'age' プロパティを除外
- 簡潔に記述できる
- 複雑なキーの除外には向かない
どの方法を選択すべきか
どの方法を選択すべきかは、状況によって異なります。
- 単純なキーの除外であれば、型エイリアスを利用するのがおすすめです。
- 柔軟性のあるキーの除外処理が必要な場合は、ジェネリック型がおすすめです。
- コード量を節約したい場合は、
Omit<T, K>
型がおすすめです。 - シンプルでわかりやすい方法を求める場合は、
Pick<T, K>
型がおすすめです。
上記以外にも、TypeScript には様々な機能が用意されています。詳細は、以下の公式ドキュメントを参照してください。
// オリジナルのインターフェース
interface User {
id: number;
name: string;
age: number;
email: string;
address: string;
}
// 特定のプロパティを除外したインターフェース(`Pick` を使用する)
type UserWithoutEmail = Pick<User, "id" | "name" | "age" | "address">;
// 特定のプロパティを除外したインターフェース(`Omit` を使用する)
type UserWithoutAddress = Omit<User, "address">;
// ジェネリック型を使用して、条件に応じてプロパティを除外するインターフェース
type ExcludeIf<T, K extends keyof T, Condition>(
obj: T,
condition: (key: K) => Condition
) => Pick<T, { [P in keyof T]: Condition extends true ? never : P }[keyof T]>;
// 特定の条件に基づいてプロパティを除外するインターフェース
type UserWithOptionalAddress = ExcludeIf<User, "address", (key: "address") => boolean>(
user: User,
(key) => user.address === ""
);
// 型エイリアスを使用して、単純なキーの除外を行うインターフェース
type UserWithoutEmailAndAddress = {
id: User["id"];
name: User["name"];
age: User["age"];
};
UserWithoutEmailAndAddress
インターフェースは、型エイリアスを使用してemail
とaddress
プロパティを除外しています。UserWithOptionalAddress
インターフェースは、ジェネリック型と条件式を使用して、address
プロパティが空文字列の場合は除外するようにしています。
インデックスシグネチャを利用することで、インターフェースに動的なプロパティを定義することができます。この機能を利用して、除外したいキーを個別に指定することができます。
interface OriginalInterface {
[key: string]: any; // 動的なプロパティを許可
id: number;
name: string;
age: number;
email: string;
address: string;
}
type RemovedEmailInterface = {
[key in Exclude<keyof OriginalInterface, "email">]: OriginalInterface[key];
};
- インデックスシグネチャの理解が必要
Partial 型と Required 型を利用する
Partial
型と Required
型を利用することで、インターフェースのプロパティの一部をオプションにすることができます。この機能を利用して、除外したいキーをオプションにすることができます。
interface OriginalInterface {
id: number;
name: string;
age: number;
email: string;
address: string;
}
type RemovedEmailInterface = Partial<OriginalInterface> & { id: number; name: string; age: number; }; // 'email' プロパティをオプションに
Partial
型とRequired
型の理解が必要- 除外したキーが完全に削除されない
ユニオン型を利用する
ユニオン型を利用することで、複数のインターフェースを組み合わせることができます。この機能を利用して、除外したいキーを含むインターフェースと、除外しないキーを含むインターフェースを組み合わせることができます。
interface UserWithAddress {
id: number;
name: string;
age: number;
address: string;
}
interface UserWithoutAddress {
id: number;
name: string;
age: number;
}
type User = UserWithAddress | UserWithoutAddress; // 'address' プロパティはオプションに
- 柔軟性のあるインターフェースの定義が可能
- ユニオン型の理解が必要
外部ライブラリを利用する
ts-essentials
のような外部ライブラリには、インターフェースからキーを除外するためのユーティリティ関数が用意されています。これらのライブラリを利用することで、より簡潔にコードを書くことができます。
import { Omit } from "ts-essentials";
interface OriginalInterface {
id: number;
name: string;
age: number;
email: string;
address: string;
}
type RemovedEmailInterface = Omit<OriginalInterface, "email">;
- コードが簡潔になる
- 外部ライブラリの導入が必要
typescript