項目64 名前的型付けのためにブランドを使うことを検討する
名前的型付け(nominal type)では、ある型を持つのは、その値がその型を持つと宣言されたからであって、その型を同じ形状にしているからではない
構造的型付けではカバーできない欠点を補う存在
下記の欠点を補える
code:ts
interface UserId {
id: number
}
interface PostId {
id: number
}
const postId: PostId = {id: 1}
const userId: UserId = postId // 構造が一緒なので区別できないためエラーにならない
意味的には異なるが、構造的には一致するプリミティブ型やオブジェクト型を区別するために、ブランドをつけることを検討する
ブランド=名前的片付け
code:ts
type UserId = {id: number} & {_brand: 'userid'}
const postId: PostId = {id: 1}
const userId: UserId = postId // _brandの型により、構造が一致しないのでエラーになる
オブジェクト型のプロパティ、文字列のenum、プライベートフィールド、unique symbolなど、ブランドを付けるのに様々なテクニックがある
個人的にはunique symbolを使うパターンが好き
code:ts
declare const brand: unique symbol;
export type Meters = number & {brand: 'meters'};
unique symbolはTypeScriptの型システムにおいて「一意なシンボル」を表す。
なので、unique symbolを使ってブランドを表現する際は、その型をエクスポートして使わないと等価であることが表現できないという制約をもうけることができるため
code:ts
//ファイルA
declare const brand: unique symbol;
export type Meters = number & {brand: 'meters'};
//ファイルB
declare const brand: unique symbol;
export type Meters = number & {brand: 'meters'}; //ファイルAの型とは別物として扱われる
#TypeScript