TypeScript インターフェースで 2 つのプロパティのいずれか 1 つを必須にする
TypeScript インターフェースで 2 つのプロパティのいずれか 1 つを必須にする
ここでは、2 つの方法でこの条件を設定する方法を解説します。
Partial と Required を組み合わせる
1 つ目は、Partial
と Required
型を利用する方法です。
interface MyInterface {
// どちらか1つが必須
prop1?: string;
prop2?: number;
}
// どちらか1つを必ず指定する
const obj: Required<MyInterface> = {
prop1: "Hello",
// prop2: 123 // エラー: 'prop2' は必須です
};
上記の例では、MyInterface
インターフェースは prop1
と prop2
という 2 つのプロパティを持ちます。どちらも ?
を付けているため、省略可能です。
しかし、Required
型を使って obj
変数を宣言すると、MyInterface
の すべてのプロパティが必須になります。つまり、prop1
と prop2
のいずれか 1 つは必ず指定する必要があります。
keyof と never を組み合わせる
interface MyInterface {
[prop in "prop1" | "prop2"]: string | number;
}
// どちらか1つを必ず指定する
const obj: MyInterface = {
prop1: "Hello",
// prop2: 123 // エラー: 'prop2' は 'prop1' または 'prop2' のいずれかである必要があります
};
上記の例では、MyInterface
インターフェースは keyof
型を使って、prop1
と prop2
という 2 つの文字列リテラルをキーとするオブジェクトとして定義されています。
[prop in "prop1" | "prop2"]: string | number
という部分は、prop1
または prop2
のいずれかのキーを持つオブジェクトであり、値は string
または number
型であることを意味します。
この方法では、obj
変数を宣言する際に、prop1
と prop2
の いずれか 1 つ を必ず指定する必要があります。
これらの方法を使い分けることで、TypeScript インターフェースで 2 つのプロパティのいずれか 1 つを必須にすることができます。状況に応じて適切な方法を選択してください。
Partial と Required を組み合わせる
interface User {
name: string;
email?: string;
age?: number;
}
// すべてのプロパティが必須
const requiredUser: Required<User> = {
name: "John Doe",
email: "[email protected]",
age: 30,
};
// name は必須、email と age は省略可能
const partialUser: Partial<User> = {
name: "Jane Doe",
email: "[email protected]",
};
// name は必須、email と age は存在しない
const partialUser2: Partial<User> = {
name: "John Doe",
};
console.log(requiredUser); // { name: 'John Doe', email: '[email protected]', age: 30 }
console.log(partialUser); // { name: 'Jane Doe', email: '[email protected]' }
console.log(partialUser2); // { name: 'John Doe' }
keyof と never を組み合わせる
interface User {
[prop in "name" | "email" | "age"]: string | number;
}
// どちらか1つを必ず指定する
const user: User = {
name: "John Doe",
email: "[email protected]",
};
// エラー: 'address' は 'name' または 'email' または 'age' のいずれかである必要があります
const invalidUser: User = {
address: "123 Main Street",
};
console.log(user); // { name: 'John Doe', email: '[email protected]' }
その他の例
Partial
とPick
を組み合わせる: 特定のプロパティのみを必須にする場合Readonly
とRequired
を組み合わせる: オブジェクトのプロパティを編集不可にする場合
TypeScript インターフェースで 2 つのプロパティのいずれか 1 つを必須にするその他の方法
条件付き型
type MyInterface = {
prop1: string;
} | {
prop2: number;
};
// どちらか1つを必ず指定する
const obj: MyInterface = {
prop1: "Hello",
// prop2: 123 // エラー: 'prop1' または 'prop2' のいずれかが必要です
};
上記の例では、条件付き型を使って、prop1
と prop2
のいずれか 1 つを持つオブジェクトを定義しています。
type MyInterface = { prop1: string; } | { prop2: number; }
という部分は、prop1
プロパティを持つオブジェクトか、prop2
プロパティを持つオブジェクトのいずれかであることを意味します。
discriminated union
interface MyInterface {
type: "prop1" | "prop2";
prop1?: string;
prop2?: number;
}
// どちらか1つを必ず指定する
const obj: MyInterface = {
type: "prop1",
prop1: "Hello",
// prop2: 123 // エラー: 'type' が "prop2" の場合のみ 'prop2' を指定できます
};
// どちらか1つを必ず指定する
const obj2: MyInterface = {
type: "prop2",
prop2: 123,
// prop1: "Hello" // エラー: 'type' が "prop1" の場合のみ 'prop1' を指定できます
};
上記の例では、discriminated union を使って、type
プロパティによってオブジェクトの種類を判別するインターフェースを定義しています。
type MyInterface = { type: "prop1" | "prop2"; prop1?: string; prop2?: number; }
という部分は、type
プロパティが "prop1"
または "prop2"
のいずれかの値を持つオブジェクトであることを意味します。
prop1
と prop2
プロパティは 省略可能ですが、type
プロパティの値によって、どちらか 1 つを必ず指定する必要があります。
ファクトリー関数
function createMyInterface(prop1: string): MyInterface {
return {
type: "prop1",
prop1,
};
}
function createMyInterface(prop2: number): MyInterface {
return {
type: "prop2",
prop2,
};
}
// どちらか1つを必ず指定する
const obj: MyInterface = createMyInterface("Hello");
// どちらか1つを必ず指定する
const obj2: MyInterface = createMyInterface(123);
createMyInterface(prop1: string)
と createMyInterface(prop2: number)
という 2 つのファクトリー関数は、それぞれ prop1
と prop2
プロパティを持つオブジェクトを返します。
obj
と obj2
変数を宣言する際に、いずれか 1 つのファクトリー関数 を必ず呼び出す必要があります。
これらの方法を使い分けることで、状況に応じて適切な方法を選択することができます。
typescript