TypeScriptでオプショナルオブジェクトを埋めるときsatisfiesを使うとグッド

satisfies の使いどころをメモする。たまにしか使わないから忘れがちだけど思い出すと便利なときがたまにある。

satisfiesとは

他者のスライドだがこれがわかりやすいと思う。

使いどころ

例えばライブラリを作っていて、configの定義がありデフォルトのオプションもあって、ユーザーはオプションを上書きできるというシーンを想定する。

そうすると、configの型は厳密で、ユーザー側の型はすべてオプションオブジェクトになる。

type Config = {
  foo: number;
  bar: string;
  baz: string[];
};

type OptionalConfig = Partial<Config>;

2つ例を書く。どちらもエディタの補完は効くが、変数の結果の型が違う。前者は Partial<Config> になるが、後者はConfig型をベースに非オプショナルな中身のみになる。

const myWidenConfig: OptionalConfig = {
  bar: "baaar",
  baz: ["b", "a", "z"],
};

これはTSコンパイラではこのように解釈される。当たり前にPartialのままで、実体の変数ではfooプロパティは定義していないし型でも未定義のままになる。

satisfies を使うとこう書くことができる。

const mySatisConfig = {
  bar: "baaar",
  baz: ["b", "a", "z"],
} satisfies OptionalConfig;

これはTSコンパイラではこのように解釈される。Config型をベースに定義したものだけが入っていてundefinedではなくなっており、fooに関する情報はない。

なので、例えばオプショナルではないConfigのプロパティを期待するところにこうやって気持ちよく挿せる。

どちらもランタイムでは非undefinedだが、pleaseBar1のほうは型エラーになる。一方pleaseBar2のほうはsatisfiesを介しているので補完が効いた上で非undefinedを表現できている。

手元で理解するには

プレイグラウンドを見るのがよいと思う