naoki.dev

記事検索

タイトル・本文・タグから検索します

ホームに戻る
バックエンド

TypeScript の satisfies で「型チェック」と「推論の保持」を両立する

目次

satisfies は「値がある型に適合しているか検査しつつ、変数の推論結果は具体的な型のまま保つ」ための演算子です。TypeScript 4.9 で追加されました。型注釈(: T)だと推論が型 T に広がってしまう場面で効きます。

何が嬉しいのか

設定オブジェクトでよくある悩みを例にします。値の形は検証したいが、各プロパティの具体的な型も失いたくない、というケースです。

type Color = [number, number, number] | string;
 
const palette = {
  primary: [234, 88, 12],
  text: "#18181b",
} satisfies Record<string, Color>;
 
palette.primary.map((v) => v / 255); // OK: primary は number[] と分かる
palette.text.toUpperCase(); // OK: text は string と分かる

Record<string, Color>適合しているかは検査されつつ、palette.primarynumber[]palette.textstring具体的に推論されたままです。

型注釈(: T)との違い

同じことを型注釈でやると、推論が Color(ユニオン)に広がってしまいます。

const palette: Record<string, Color> = {
  primary: [234, 88, 12],
  text: "#18181b",
};
 
palette.primary.map((v) => v); // エラー: primary は Color 型。number[] とは限らない

型注釈は「変数の型を T に固定する」ため、リテラルや配列の具体情報が消えます。satisfies は「T に適合するかだけを見て、変数の型は推論に任せる」ので、両取りできます。

キーの過不足・タイポも検出できる

Record<Union, string> と組み合わせると、キーの抜け漏れやスペルミスを型エラーにできます。

type Route = "home" | "about" | "contact";
 
const titles = {
  home: "ホーム",
  about: "について",
  contact: "お問い合わせ",
} satisfies Record<Route, string>;
 
titles.home.length; // OK: 値は string と推論される

aboutabuot と打ち間違える、あるいは contact を書き忘れると、その場でエラーになります。それでいて titleshome / about / contact を持つ具体的な型のままです。

3つの比較

書き方 型チェック 推論を具体型で保持
型注釈 : T ✗(T に広がる)
as T ✗(強制キャスト)
satisfies T

as は「コンパイラを黙らせる」ためのもので検査はされません。satisfies は検査を保ったまま推論も活かせる点が決定的に違います。

いつ使うか

  • 設定・定数オブジェクト(カラーパレット、ルート定義、辞書テーブルなど)
  • 「形は守りたい」かつ「個々の値の具体型も使いたい」とき

逆に、関数の引数や戻り値のように型を固定したい場面は、従来どおり型注釈を使えば十分です。

まとめ

satisfies は「適合性の検査」と「推論結果の保持」を両立する演算子です。設定オブジェクトに添えるだけで、タイポを防ぎつつ具体的な型を保てます。as で握りつぶしていた箇所こそ、satisfies への置き換えを検討する価値があります。

関連記事