Code Fix

中級

文字列リテラルをenum型の引数に渡すとエラーになる理由

enumで定義した型は、見た目が近い文字列リテラルであっても別の型として扱われます。enumのメンバー名と同じ文字列を渡しても、enum型そのものの値でなければ代入・引数として受け付けられません。

エラーメッセージの読み方

main.ts(8,20): error TS2345: Argument of type '"Active"' is not assignable to parameter of type 'Status'.
main.ts
ファイル名
8
行番号
20
列番号 — この位置でtscが検査に失敗しました
TS2345
エラーコード — 検索するとTypeScriptの解説が見つかります
Argument of type '"Active"' is not assignable to parameter of type 'Status'.
内容 — 期待していたもの、または受け付けられなかったもの

このエラーが出る典型パターン

パターン1

 1  enum Status {
 2    Active,
 3    Inactive,
 4  }
 5  function report(s: Status): string {
 6    return `status=${s}`;
 7  }
 8  console.log(report("Active"     ));
                             ^
main.ts(8,20): error TS2345: Argument of type '"Active"' is not assignable to parameter of type 'Status'.

"Active"はただの文字列であり、enumのStatus.Activeとは別の型です。メンバー名と同じ文字列を渡しても通用しません。

直し方: "Active" を Status.Active にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  enum Color {
 2    Red,
 3    Blue,
 4  }
 5  function paint(c: Color): string {
 6    return `color=${c}`;
 7  }
 8  console.log(paint("Red"    ));
                          ^
main.ts(8,19): error TS2345: Argument of type '"Red"' is not assignable to parameter of type 'Color'.

文字列の"Red"とColor.Redは別の型です。enumのメンバーそのものを渡す必要があります。

直し方: "Red" を Color.Red にします。

この問題を解いてみる →

パターン3

 1  enum Level {
 2    Low,
 3    High,
 4  }
 5  function setLevel(l: Level): string {
 6    return `level=${l}`;
 7  }
 8  console.log(setLevel("Low"    ));
                             ^
main.ts(8,22): error TS2345: Argument of type '"Low"' is not assignable to parameter of type 'Level'.

Level.Lowと文字列"Low"は別の型として扱われます。setLevelにはenumの値そのものを渡す必要があります。

直し方: "Low" を Level.Low にします。

この問題を解いてみる →

パターン4

 1  enum Mode {
 2    Auto,
 3    Manual,
 4  }
 5  function setMode(m: Mode): string {
 6    return `mode=${m}`;
 7  }
 8  console.log(setMode("Auto"   ));
                            ^
main.ts(8,21): error TS2345: Argument of type '"Auto"' is not assignable to parameter of type 'Mode'.

"Auto"はただの文字列であり、enumのMode.Autoとは別の型です。

直し方: "Auto" を Mode.Auto にします。

この問題を解いてみる →

パターン5

 1  enum Size {
 2    Small,
 3    Large,
 4  }
 5  function pick(s: Size): string {
 6    return `size=${s}`;
 7  }
 8  console.log(pick("Small"   ));
                          ^
main.ts(8,18): error TS2345: Argument of type '"Small"' is not assignable to parameter of type 'Size'.

文字列の"Small"とSize.Smallは別の型です。enumのメンバーそのものを渡す必要があります。

直し方: "Small" を Size.Small にします。

この問題を解いてみる →

よくある誤解

「enumのメンバー名と同じ文字列を渡せば通じるはず」という考えは誤りです。TypeScriptのenumは独自の名前的型(nominal-ishな型)を持ち、文字列リテラル型とは構造が似ていても別物として扱われます。

実務での勘所

TypeScriptのコミュニティでは、enumの代わりに文字列リテラルのunion型(type Status = "active" | "inactive";)を使うことを推奨する意見が広がっています。リテラルユニオンは普通の文字列リテラルとして扱えるため、このトピックのような「見た目は同じ文字列なのに型が違う」という混乱が起きません。enumはコンパイル後に実体を持つオブジェクトを生成するなど独自の癖も多く、新しいコードではenumより文字列リテラルのunion型を選ぶスタイルガイドが増えています。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)