Code Fix

中級

switchで一部returnを書き忘れた原因と直し方

union型の値をswitch文で分岐する関数で、一部のケースにしかreturnを書かないと、「関数がreturn文で終わっていない」というエラーになります。TypeScriptはunion型の全パターンをたどって、返し忘れがないかを検査します。

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

main.ts(2,26): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.
main.ts
ファイル名
2
行番号
26
列番号 — この位置でtscが検査に失敗しました
TS2366
エラーコード — 検索するとTypeScriptの解説が見つかります
Function lacks ending return statement and return type does not include 'undefined'.
内容 — 期待していたもの、または受け付けられなかったもの

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

パターン1

 1  type Shape = { kind: "circle"; radius: number } | { kind: "square"; side: number };
 2  function area(s: Shape): number {
 3    switch (s.kind) {
 4      case "circle":
 5        return Math.PI * s.radius * s.radius;
 6                                                  
                            ^
 7    }
 8  }
 9  console.log(area({ kind: "square", side: 4 }));
main.ts(2,26): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.

squareのケースにreturnが無いため、switch文が値を返さずに終わる経路が生まれます。全パターンをカバーしていないとtscが検出します。

直し方: (空) を case "square": return s.side * s.side; にします。

この問題を解いてみる →

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

パターン2

 1  type Payment = { kind: "card" } | { kind: "cash" };
 2  function fee(p: Payment): number {
 3    switch (p.kind) {
 4      case "card":
 5        return 3;
 6                                  
                    ^
 7    }
 8  }
 9  console.log(fee({ kind: "cash" }));
main.ts(2,27): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.

cashのケースを網羅していないため、switch文を抜けてもreturnされない経路があります。

直し方: (空) を case "cash": return 0; にします。

この問題を解いてみる →

パターン3

 1  type Level = { kind: "low" } | { kind: "high" };
 2  function score(l: Level): number {
 3    switch (l.kind) {
 4      case "low":
 5        return 1;
 6                                   
                    ^
 7    }
 8  }
 9  console.log(score({ kind: "high" }));
main.ts(2,27): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.

highのケースを書き忘れると、その経路でreturnされずに関数が終わってしまいます。

直し方: (空) を case "high": return 10; にします。

この問題を解いてみる →

パターン4

 1  type Light = { kind: "red" } | { kind: "green" };
 2  function action(l: Light): string {
 3    switch (l.kind) {
 4      case "red":
 5        return "stop";
 6                                      
                      ^
 7    }
 8  }
 9  console.log(action({ kind: "green" }));
main.ts(2,28): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.

greenのケースにreturnが無いため、switch文が値を返さずに終わる経路が生まれます。

直し方: (空) を case "green": return "go"; にします。

この問題を解いてみる →

パターン5

 1  type Media = { kind: "audio" } | { kind: "video" };
 2  function play(m: Media): string {
 3    switch (m.kind) {
 4      case "audio":
 5        return "sound";
 6                                          
                        ^
 7    }
 8  }
 9  console.log(play({ kind: "video" }));
main.ts(2,26): error TS2366: Function lacks ending return statement and return type does not include 'undefined'.

videoのケースを網羅していないため、switch文を抜けてもreturnされない経路があります。

直し方: (空) を case "video": return "stream"; にします。

この問題を解いてみる →

よくある誤解

「該当しないケースは実行時に来ないはずだから、書かなくても大丈夫」という判断は、tscの型チェックには通用しません。実行時の可能性ではなく、型として定義された全パターンを静的に検査します。

実務での勘所

このエラーは、union型に特化した特別な検査ではなく、C#やJavaにもある「全ての経路が値を返しているか」という一般的な制御フロー解析の一例です。switchの一部のcaseだけにreturnがあると、該当しなかった残りのcaseがreturn文を経由せずに関数の末尾へ抜けてしまいます。union型の全パターンを網羅していないこと自体は間接的な結果であって、直接検出されているのは「returnせずに関数の外に出る経路が存在する」という、より一般的な制御フローの問題です。

演習をはじめる

関連するエラー

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