項目34 ユニオンを含むインターフェイスよりも、インターフェイスのユニオンを選択する
複数のユニオン型のプロパティを持つインターフェースは、他に良い定義ができない検討するべき
この状態は、プロパティ感に存在する関係を明確に表現できていない可能性がある
レイヤーの描画情報を表すインターフェースを例に考える
悪いインターフェース
下記のlayoutとpaintは同じ接頭辞の型の組み合わせが期待されているが型で縛りを設けることができていない
code:ts
interface Layer {
layout: FillLayout | LineLayout | PointLayout;
paint: FillPaint | LinePaint | PointPaint;
}
良いインターフェース
それぞれのタイプのレイヤーごとにインターフェースを用意することで不正な組み合わせが生まれなくなった
詳しくは項目29 有効な状態のみ表現する型を作る
code:ts
interface FillLayer {
layout: FillLayout;
paint: FillPaint;
}
interface LineLayer {
layout: LineLayout;
paint: LinePaint;
}
interface PointLayer {
layout: PointLayout;
paint: PointPaint;
}
type Layer = FillLayer | LineLayer | PointLayer;
文字付きリテラル型のユニオンで様々なtypeの型を表現しようとする場合も検討が必要
悪いインターフェース
code:ts
interface Layer {
type: 'fill' | 'line' | 'point';
layout: FillLayout | LineLayout | PointLayout;
paint: FillPaint | LinePaint | PointPaint;
}
良いインターフェース
code:ts
interface FillLayer {
type: 'fill';
layout: FillLayout;
paint: FillPaint;
}
interface LineLayer {
type: 'line';
layout: LineLayout;
paint: LinePaint;
}
interface PointLayer {
type: 'paint';
layout: PointLayout;
paint: PointPaint;
}
type Layer = FillLayer | LineLayer | PointLayer;
TypeScriptでタグ付きユニオンを使って、データ型を表現できるのなら、その方法を優先する
データをより正確にモデリングするために、複数のオプションプロパティをグループ化できないか検討する
悪いインターフェース
項目31 型情報をドキュメントで繰り返さないに記載したように、型情報を含むコメントが生まれる場合は、型自体に問題があることが多い
code:ts
interface Person {
name: string;
// これらは両方とも存在するか、両方とも存在しない
placeOfBirth?: string;
dateOfBirth?: Date;
}
良いインターフェース
複数のオプションプロパティは1つのオブジェクトにまとめることで、意図しない組み合わせが生まれることを防ぐ
code:ts
interface Person {
name: string;
birth?: {
place: string;
date: Date;
}
}
下記のように、インターフェースのユニオンを使ってオプションプロパティを表現する方法もある
code:ts
interface Name {
name: string;
}
interface PersonWithBirth extends Name {
placeOfBirth: string;
dateOfBirth: Date;
}
type Person = Name | PersonWithBirth;
#TypeScript