UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【FlowType】EnumのValueのUnion型をつくる

以前にEnumのようなUnion型を生成する方法を調べた

【FlowType】逆引きメモ - UGA Boxxx

このとき、Keyの型チェックに対しては$Keysを使うことがわかったが、Valueに対しての型チェックはどうやるのかがわからなかったので調べたら、単純に$Valuesを使えばよいだけではなかったので別でまとめることにした

やり方はこちらの記事が参考になった

nobitagit.github.io

下のような定数オブジェクトに対して、

const statuses = {
  APPROVED: 'approved',
  REJECTED: 'rejected',
  PENDING: 'pending'
};

こういう型を作りたいが、

type Status = 'approved' | 'rejected' | 'pending';

ハードコーディングしていると変更が大変なのでうまくやりたい

冒頭でいったように$Valuesを使えばよいかと考えたが、うまく型チェックされない

const statuses = {
  APPROVED: 'approved',
  REJECTED: 'rejected',
  PENDING: 'pending'
};
type Status = $Values<typeof statuses>;
const status1: Status = "approved"; // Work!
const status2: Status = "nope"; // Work!?

理由として、

Flowの中でプロパティをもったオブジェクトを生成すると、それをsealed objectとして扱うため
つまり、プロパティの変更が可能である限り、型の推測はできるが値は推測できない

sealed objectとは新しいキーを追加することができないオブジェクト。ただし、既存の値を変更することはできる。

なので、次のようにオブジェクトをfreezeさせるとよいとのこと

const statuses = Object.freeze({
  APPROVED: 'approved',
  REJECTED: 'rejected',
  PENDING: 'pending'
});

ただし、このfreezeオブジェクトとtypeが別ファイルだと機能しなくなるので同じファイルに置く必要がある