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.primary は number[]、palette.text は string と具体的に推論されたままです。
型注釈(: 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 と推論されるabout を abuot と打ち間違える、あるいは contact を書き忘れると、その場でエラーになります。それでいて titles は home / about / contact を持つ具体的な型のままです。
3つの比較
| 書き方 | 型チェック | 推論を具体型で保持 |
|---|---|---|
型注釈 : T |
✓ | ✗(T に広がる) |
as T |
✗(強制キャスト) | ✗ |
satisfies T |
✓ | ✓ |
as は「コンパイラを黙らせる」ためのもので検査はされません。satisfies は検査を保ったまま推論も活かせる点が決定的に違います。
いつ使うか
- 設定・定数オブジェクト(カラーパレット、ルート定義、辞書テーブルなど)
- 「形は守りたい」かつ「個々の値の具体型も使いたい」とき
逆に、関数の引数や戻り値のように型を固定したい場面は、従来どおり型注釈を使えば十分です。
まとめ
satisfies は「適合性の検査」と「推論結果の保持」を両立する演算子です。設定オブジェクトに添えるだけで、タイポを防ぎつつ具体的な型を保てます。as で握りつぶしていた箇所こそ、satisfies への置き換えを検討する価値があります。
