‼️

switch文でconstは使えない!警告の正体と解決法

に公開

はじめに

こんにちは、トラマトです!
現在、Canvas APIを使ってパラメータをいじれる幾何学アートジェネレーター(Github)を作っています。

しかし、描画のアルゴリズムをswitch文で切り替えようとしたとき、こんなエラーが出てきました。

Unexpected lexical declaration in case block

え、caseの中で変数宣言しちゃダメなんすか?と最初困惑したのですが、原因と解決法、JavaScriptの仕様に納得したので備忘録としてまとめます!


遭遇したエラー

幾何学模様の形をmodeという変数で切り替えるために、こんなコードを書いていました。

このエラーの正体はTypeScriptのコンパイルエラーではなく、ESLint(コードの問題点を指摘してくれる静的解析ツール)のno-case-declarationsというルールによる警告です。

switch (mode) {
  case 'Polygon': // 多角形モード
    const sides = Math.max(3, waves);
    const a = Math.PI / sides;
    // ...描画処理...
    break;

  case 'Heart': // ハート型モード
    const r = baseRadius * 0.1;
    // ...描画処理...
    break;
}

原因: switch文は全部ぶち抜く仕様だった

ちょっと前に大学でC言語を触っていた感覚だと、「caseごとに処理は別なんだから、変数も別物なのでは?」と思ってしまいます。
しかしなんと、JavaScript(TypeScript)の仕様では、switch文全体で1つのスコープを共有していたのです。

// ↓この { から
switch (mode) { 
  case 'Polygon':
    const sides = 3;
    const a = 10;
    break;

  case 'Heart':
    const r = 5; // ← 同じ空間に sides, a, r が混在してしまっている
    break;
// ↓この } までが同じ1つの空間
}

constletブロックスコープ({}の中だけで有効な変数) を作るための宣言です。
しかし、このままではPolygon用の変数もHeart用の変数も同じ部屋に散らかっている状態になり、関数名の衝突などのバグの温床になります。
だからしっかりとUnexpected lexical declarationという警告を出してくれていたわけですね〜


解決法: caseごとにブロックを作る

原因が「同じ部屋だから」なので、解決法は至ってシンプル。以下のようにcaseの中に壁を作ってあげればOKです。

switch (mode) {
  case 'Polygon': {  // ← { を追加してブロックスコープを作る!
    const sides = Math.max(3, waves);
    const a = Math.PI / sides;
    break;
  }                  // ← } で閉じる

  case 'Heart': {    // ← ハート用にも個室を作る
    const r = baseRadius * 0.1;
    break;
  }                 // ← こっちも閉じる!
}

caseの中身を{ }で囲むだけ!
これだけで独立したブロックスコープが生まれるので、例えばPolygonの部屋で作ったsidesという変数が他の部屋に影響を与えなくなります。エラーも綺麗に消え去りますね。


まとめ

  • switch文の各caseは、デフォルトでは同じスコープを共有している
  • これにより、そのままconstletを使うとスコープが混ざりエラーを吐く
  • caseの中身を{ }で囲うだけで独立したスコープとなり、安全な変数宣言が可能になる

基礎的なことですが、TypeScriptのエラーから「なぜダメなの??」を深堀りすると、言語についてより詳しくなれるような気がするので面白いですね。

引き続き、幾何学アートジェネレーターの完成を目指してゴリゴリ書きまくっていきます!

それでは!

GitHubで編集を提案

Discussion