• 作成:

TypeScript 4.9からはsatisfies演算子でパターンの網羅性をESLintと共存しつつ簡単にチェックできる

背景

私はAWS CDKを利用する時にデプロイステージをよく以下のように分けています。

export const stages = ["deve", "stag", "prod"] as const;
/**
 * 開発用、本番用などを分けるステージ
 * {@link https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Stage.html} は一切関係がない
 */
export type Stage = typeof stages[number];

こうするとstagesを反復することで簡単に全てのステージに対してスタックを作ることが可能ですし、その名前にStagestringとして埋め込んで区別することが可能です。

引数ではstringではなくStageを受け取ってstage === "deve"のように比較すれば、リテラル型となっているのでtypoを防ぐことが可能です。

問題

この間switch(stage)で処理を分けていた時、 ESLintが怒ってくるため、

TypeScriptのexhaustiveness checkをスマートに書くみたいな黒魔術を見てビビってました。

しかしTypeScript 4.9からは割と簡単に書けることを教えてもらいました。

今回の場合は単純に、

switch (stage) {
  case "deve":
    return deve;
  case "stag":
    return stag;
  case "prod":
    return prod;
  default:
    throw new Error(stage satisfies never);
}

とすれば良かったです。ちゃんとcase網羅しないとエラーになります。

lspの読み込むバージョンが古くてトラブル

コマンドライン上のlintではTypeScriptとprettierをアップデートすることで問題なくなったのですが、 Emacsのlsp-modeのTypeScript lspがエラーを出し続けて、 language serverを更新してもエラーを出して困惑しました。

しかし*lsp-log*を見て納得しました。

何故かグローバルにインストールされたTypeScriptコンパイラを優先的に読み込んでしまっていました。グローバルに使うこともないやと最近グローバルにインストールするスクリプトからもTypeScriptコンパイラは削除したので、 yarn global remove typescript で解決しました。

雑にts-nodeを使いたくなったらどうしようかなと思いましたが、それぐらいならyarn dlxを使えば良いですかね。

これバグ報告した方が良いのだろうか、しかしもうグローバルにインストールするのはとにかくやめろみたいな風習がありますし悩みどころですね。

as constが既についている配列にsatisfiesを付けるモチベーションが分からない

記事を漁っていると私のstagesみたいな変数にas constだけではなくsatisfiesを付けるパターンを見ましたが、 as constしてる時点でリテラル型になっているため、オブジェクト型ならともかく配列型につけるモチベーションは今ひとつ分かりませんでした。