TypeScriptで同じ構造の型を区別する
モチベーション
TypeScriptで同じ構造の型を区別したい
例えば、以下のようなもの
UserIdとPostIdという2つの型を定義している
しかし、TypeScriptは構造的部分型を採用しているため、これらは区別されない
code:ts
type UserId = number;
type PostId = number;
const userId: UserId = 888;
const postId: PostId = 24;
const register = (userId: UserId, postId: PostId) => {...}
register(postId, userId) // 引数の順番をミスっているがerrorにならない
いくつかの実現方法
branded types
flavor type
libraryを使う
newtype-ts
Deep Diveで紹介されているやつ
これはだいぶ簡易
code:ts
type Id<T extends string> = {
type: T,
value: string,
}
いくつかの問題を抱えていると思うmrsekut.icon
値の構造が変わっているのでruntimeに影響がある
constructorがなくとも容易にその構造を作成できてしまう
構造が貧弱なので、たまたま被る可能性が高い
typeやkindは、Tagged Unionする時にあるあるすぎる
応用
「同じ構造をの型を別物として扱う」ことで、設計を堅牢にする様々な工夫ができるようになる
上の「モチベーション」は本当に表層のことしか書いていないmrsekut.icon
例えば、smart constructorを使って、検証済みであることを型で明示するなど
ref frontendでも外部との境界で、仕様を満たした型に変換する
Nominal Subtypingをサポートしてくれという趣旨のissueが2014/7/23に立てられている
Support some non-structural (nominal) type matching · Issue #202 · microsoft/TypeScript · GitHub
ずっとopenになってる
#WIP
#??
この辺との違い
公称的部分型
幽霊型
幽霊型では、タグとして引数に与えるのは基本的に型だが、
TypeScriptではstring literal typeを与えることが多い
タグが重複すれば同等のものになる、という特性はbranded typeも同じ
newtype
newtypeはそもそも新しい型を生成する
TypeScriptでは無理
TypeScriptでは元々用意されているprimitive型のsubtypingでしか新しい型を定義できない