as const satisfiesの話
こんにちは。CURUCURUエンジニアの長尾です。 最近あまりネタがなくなってきましたので勉強がてらtypescriptの文法のお話をしようと思います。
概要
as const satisfies
のお話。
as const とは
as const
を使うとオブジェクトプロパティがreadonlyになるという機能です。
使い方
const test = {
yamada: 100,
suzuki: 90,
saitou: 80,
} as const;
上記のように定義した場合、test
オブジェクトは定数なのでそのままtest.yamada
とかで使えますよね。
そして、この変数を使ってunion型を作りたいときがあった場合、以下のようにすると思います。
type TestKey = keyof typeof test;
これは
type TestKey = 'yamada' | 'suzuki' | 'saitou';
と同じ意味です。
では、これのvalue版はどうかというと。以下です。
type TestValue = typeof test[TestKey];
これは
type TestValue = 100 | 90 | 80;
と同じ意味です。
ここで面白いのがas const
をつけない場合にvalueのunion型を作ると
type TestValue = number;
と同じ意味になってしまい、推論結果が意図したものになっていないです。(number型を意図していたのなら話は別です)
これは「Widening」と呼ばれる型の拡張です。
as const
をつけることで型の拡張を止めることができるため正しく型を作ることができます。
satisfies
typescript4.9から追加されたものでsatisfies
というものがあり、これをas const
と使うととても型安全になります。
as const
はWideningを防ぐ効果がありましたが、satisfies
は定義した型を満たしているかどうかをチェックすることができます。
型のチェックがないのでendouさんにstring型の"80"を与えることが出来てしまいます。
const test = {
yamada: 100,
suzuki: 90,
saitou: 80,
endou: "80",
};
なのでこれを
type Test = { [key in string]: number };
const test = {
yamada: 100,
suzuki: 90,
saitou: 80,
endou: "80",
} satisfies Test;
とすることで型安全になります。
satisfies
と同じような意味で違う文法として型注釈
があります。
const test: Test = {
yamada: 100,
...
}
と書く方法ですね。
型注釈
では、例えば
type Test = { [key in string]: number | number[] };
const test: Test = {
yamada: 100,
suzuki: 90,
all: [100, 90],
};
と書いた場合、allに対してmapを使うことが出来ません。
function GetPerfect() {
return test.all.filter(t => t === 100);
}
をしたくても
プロパティmapはnumber型に存在しません
とエラーが出ます。
これを解消するにはsatisfies
を使います。そうすると型の推論結果(ここではallがnumber[]であること)を保持してくれるため、エラーがでなくなります。
言いたいこと
as const satisfies
を使うと型安全かつwidening防止でより安全にコーディングできそうなので、利用場面をきちんと考えて使っていきたいですね。
まとめ
ということで今回はtypescriptの文法のお話でした。 typescriptは日々新しい機能が増えていくので使いこなせるようにならないといけないですね。
以上、長尾がお届けしました。
メンバー募集
CURUCURUでは開発メンバーを募集中です。 CURUCURUの開発に興味があったり、モダンな開発環境で挑戦してみたいという方がいましたら、ぜひこちらも覗いてみてください!