LoginSignup
8
4

More than 5 years have passed since last update.

flowtypeでobject keyの取り違えを無くす

Last updated at Posted at 2017-09-04

謝辞

課題について考察してくれた @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 さんありがとうございます!

8
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4