## 気軽に使えるオプションプロパティ
以下のような既存の型に新しいプロパティを追加したいとします。
```ts
type User = {
id: number
name: string;
// avatorUrl 追加したい
}
```
この時に`?` を使用してプロパティをオプショナルに指定できます。こうすることで、`avatorUrl`がいらない既存の関数やコンポーネントなどの既存のコードに影響を与えずにプロパティを追加することができます。
```ts
type User = {
id: number;
name: string:
avatorUrl?: string
}
```
## オプショナルプロパティのデメリット
### 値の渡し忘れ
例えば`avatorUrl`が実際にはUI表示に必須だった場合でも、オプショナルにしてしまうとTypeScriptの型チェックが働かないため意図しない挙動となってしまいます。
### 組み合わせ爆発
オプショナルプロパティが複数存在する場合、その組み合わせは指数的に増加します。
例:オプショナルが10個 → 2¹⁰ = 1024通り
すべての組み合わせを網羅するのは辛いですね
### 型同士の相互作用
たとえば、「プロパティ A
がある場合は B
も必要」といった相関関係や、相互に排他的関係があるものが多いと思います。このように1つの型の中で複数の状態は可読性が低く、バグを起こしやすいコードの原因になってしまいます。
## 解決策
### 判別可能ユニオンを使用してモデリングする
上の型同士の相互作用の項目に関連しますが、TypeScriptのメリットを享受するために有効な状態のみ表現する型をつくりましょう。これにより状態が明確になり、コードが読みやすくバグを未然に防ぐ設計になります。
以下、LLM が吐いたコード例です。
#### よくない
以下のような型だと全てのプロパティの状態を考慮しなくてはならず、バグが入りやすくなります。例えば`isLoading` がtureで`data`が存在する場合、何を表示すれば良いんでしょうか...
```ts
type LoadState = {
isLoading: boolean;
data?: string;
error?: string;
};
```
#### よい
```tsx
type LoadState =
| { status: 'loading' }
| { status: 'success'; data: string }
| { status: 'error'; errorMessage: string };
const Content = (state: LoadState) => {
switch (state.status) {
case 'loading':
return <p>読み込み中</p>;
case 'success':
return <p>{state.data}</p>;
case 'error':
return <p>{state.errorMessage}</p>;
}
};
```
## オプションプロパティを使う場面
とはいえオプションプロパティを使用べき、使わざるを得ない場面も当然あります。
- APIの型を表す場合
- 巨大な設定項目
- オプションなプロパティ(例:ミドルネームなど)
## まとめ
- オプションプロパティのデメリットを理解しておく
- オプションプロパティを追加する前に必須にできないかを考える