謝辞
課題について考察してくれた @akameco さんと答えをくれた @kinzal さんに感謝!!
始まり
object key(string型)の取り違えを無くしたい。。。
何いってんの?
例えば、
APIやDBから手に入れたkey valueオブジェクトが2つあるとして。
ここではUserオブジェクトとItemオブジェクト。
const users: { [userKey: string]: {/* some value */} }
const items: { [itemKey: string]: {/* some value */} }
システムの中でkeyを取り違えたバグを埋め込んでも型安全は保証してくれない。
const user = users[itemKey] // <= 怒られたい
やりたきこと
js世界ではstringとして振る舞って、でも取り違えたら「型が違うよ!」って怒られたい!!
やったこと
Stringを拡張したKeyクラスを作り、そこからKeyクラス型を作る
const UserKeyClass = class extends String {}
const ItemKeyClass = class extends String {}
export type UserKeyType = Class<UserKeyClass>
export type ItemKeyType = Class<ItemKeyClass>
そして使う
const users: { [userKey: UserKeyType]: {/* some value */} }
const items: { [itemKey: ItemKeyType]: {/* some value */} }
これなら怒られる!!
HAPPY!!
でもこれはイケてない解決策です。
この userKey
を普通にstringとして使おうとすると怒られる。
const path = `/users/${userKey}` // <= flow「string型じゃないからだめ!」
こうすると黙る
const path = `/users/${userKey.toString()}`
String
に対して .toString()
を唱えても同じstringが手に入ることを利用してます。。。
型安全だけ手に入れてjs世界での使い心地が変わらない方法を募集しています。。。。
真の解 [2017/09/07]
Opaque Type Aliases でKey型を作る
export opaque type UserKeyType: string = string
export opaque type ItemKeyType: string = string
そして使う
const users: { [userKey: UserKeyType]: {/* some value */} }
const items: { [itemKey: ItemKeyType]: {/* some value */} }
怒られる!!
意味不明なクラス作らなくていいし、
toStringとか唱えなくていいし、
プリミティブな string
の方で定義できるし。
なんだよ最高かよ。
@kinzal さんありがとうございます!