Typescript 4.9 の satisfies Operator が気になる
🌼 はじめに
最近 TypeScript 4.9 Beta のお知らせがありましたね!
その中で新しく登場したsatisfies
がとても気になったのでざっと整理してみたいと思います。
1. Typescript のジレンマ
1番最初の文書としてこういう話が出てきます。
TypeScript developers are often faced with a dilemma: we want to ensure that some expression matches some type, but also want to keep the most specific type of that expression for inference purposes.
TypeScript経験者なら一回は出会ったことある状況かもしれません。サンプルコードで見てみましょう。
// 各プロパティは string もしくは RGB タプル型
const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ^^^^ bleu に注意!タイポしてる!
};
// 'red'には配列メソッドを使えるように使いたい
const redComponent = palette.red.at(0);
// また'green'には文字列メソッドを使えるように使いたい
const greenNormalized = palette.green.toUpperCase();
bleu
というタイポがありますね。このミスはpalette
に型アノテーションを使うことでチェックできますが、そうしたら各プロパティに関する情報が失われてしまいます。
type Colors = "red" | "green" | "blue";
type RGB = [red: number, green: number, blue: number];
const palette: Record<Colors, string | RGB> = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ~~~~ タイポが正しく検出されるようになったよ!
};
// でもここで好ましくないエラーが出てしまう
// Property 'at' does not exist on type 'string | RGB'.
// Property 'at' does not exist on type 'string'.
const redComponent = palette.red.at(0);
palette.red
が本当は配列なのに型定義がstring | RGB
になったため、配列メソッド使用のときエラーが出てます。
こういうとき「palette
のキーはColors
にマッチしてほしいけど(matches some type)、メソッド使用などのためにバリューにおける正確な型の推論は残してほしい(keep the most specific type)!」と思っちゃいますよね。似たようなケースも結構あると思います。
2. satisfies Operator
Typescript 4.9 で新しく登場したsatisfies
を使ったら式の型を変更することなく、式の型がある型と一致するかどうかをチェックすることができるらしいです。
実際の使い方はこちらです。
type Colors = "red" | "green" | "blue";
type RGB = [red: number, green: number, blue: number];
const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ~~~~ タイポが検出される!
} satisfies Record<Colors, string | RGB>;
// どちらのメソッドも相変わらず使える!
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();
satisfies
を使うとpalette
のすべてのプロパティがstring | number[]
型と互換性があるかどうかを見るようです。それで互換性があると判断したら推論を残す感じではないかと思います。
3. satisfies で解決できる問題
上で話したジレンマ状況以外にもsatisfies
で解決できる問題がいくつか紹介されてました。
例えばオブジェクトに型定義していないプロパティは持たせたくない場合、型ノーテーションを使ったら余剰プロパティチェックで探知きます。
type Colors = "red" | "green" | "blue";
const favoriteColors: Record<Colors, unknown> = {
"red": "yes",
"green": false,
"blue": "kinda",
"platypus": false //「"platypus" というのは 'Colors' にないよ」というエラー
};
// Type 'unknown' is not assignable to type 'boolean'
const g: boolean = favoriteColors.green;
余剰プロパティチェックが何かわからない方はこの記事をご参考ください。
不要なプロパティを探知できたのは良いですが、プロパティの型が全部unknown
になったのでg
の型ノーテーションでエラーになってますね。
こういうときもsatisfies
が役立つようです。
type Colors = "red" | "green" | "blue";
const favoriteColors = {
"red": "yes",
"green": false,
"blue": "kinda",
"platypus": false //「"platypus" というのは 'Colors' にないよ」というエラー
} satisfies Record<Colors, unknown>;
// 'red'、'green'、'blue'の各プロパティに関する情報はすべて保持される
const g: boolean = favoriteColors.green;
favoriteColors.green
はboolean
型だという推論が残ってるので、g
をboolean
型に宣言してもエラーにならないんんじゃないかなと推測してみます。
また、各プロパティが何らかの型に沿ってるかどうかチェックすることもできるようです。
type RGB = [red: number, green: number, blue: number];
const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0]
// ~~~~~~ エラー!
} satisfies Record<string, string | RGB>;
// 各プロパティの情報は残ってる
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();
ちゃんと指定した型通りかどうか担保できることがいいですね。
もっと多くの使用例はイシューとプルリクで確認できます。
🌷 終わり
まだsatisfies
を Typescript Playground で試せないので詳細まではわかってませんが、使える場面があるんじゃないかなと思いました。リリースされたら使ってみたいですね!
+2022.09.29 追記
と、思いましたが既にplaygroundを準備してくれた方がいらっしゃるという情報をコメントでいただきました。色々試してみたいと思います!
Discussion
はじめまして!
Playgroundを用意してくれてる方がいたので、そのリンク貼っておきます!!
はじめまして!
わざわさありがとうございます!!!!!🥺
ありがとうね、みんちゃん