ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

TypeScript の never 型を徹底解説 — 制御フロー分析・網羅性チェックとの連携

2026/9/27 10:34:56 拓冰建站 浏览量
TypeScript の never 型を徹底解説 — 制御フロー分析・網羅性チェックとの連携 文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载neverは TypeScript の中でも特に理解が難しい型の一つですが、制御フロー分析型の絞り込みと組み合わせることで、決して発生しない値や処理経路をコンパイラに正確に伝えることができます。本記事では、The Concise TypeScript Book の never 型解説を軸に、無限ループや例外投出によるneverの明示的利用、switch文での網羅性チェックexhaustiveness checkingまで、実践的なコード例とともに詳しく解説します。読み終えると、never 型を「型安全の最終防衛線」として活用し、ユニオンの拡張時に未処理ケースをコンパイルエラーとして検出できるようになります。never 型とは何かnever型は決して生成されることのない値を表す型です。TypeScript の型システムの中で、あらゆる値を持てない「空の集合」のような存在であり、void型値を返さない関数の戻り値やunknown型値が不明だが存在しうるとは根本的に意味が異なります。本リポジトリの英語版ドキュメント never-type.md では、次のように定義されています。Thenevertype represents values that never occur. It is used to denote functions or expressions that never return or throw an error.つまり never 型は、「関数が決して戻らない」「必ず例外を投げる」といった到達不能な経路や絶対に取り得ない値を型レベルで表現するために使われます。制御フロー分析による never 型の推論ユニオン型の変数を絞り込みnarrowingしていくと、最後に「どの候補型にも該当しない」状態に到達することがあります。このとき TypeScript コンパイラは、その変数はnever型でなければならないと推論します。これは日本語版の章 the-never-type.md の冒頭で述べられている通りです。以下の例は、string | numberのユニオン型を受け取る関数です。typeofによる絞り込みをstring→numberと順に行うと、最後のelseブロックに到達できる値は存在しません。そこで TypeScript は変数valの型をneverと推論します。const printValue (val: string | number) { if (typeof val string) { console.log(val.toUpperCase()); } else if (typeof val number) { console.log(val.toFixed(2)); } else { // val has type never here because it can never be anything other than a string or a number const neverVal: never val; console.log(Unexpected value: ${neverVal}); } };このコードのポイントは、elseブロックの中でconst neverVal: never val;と明示的にnever型へ代入している点です。valはstringでもnumberでもない値を持ち得ないため、この代入は型エラーになりません。逆に言えば、もしこの関数が実際にstringでもnumberでもない値たとえばbooleanを引数に受け取れる設計だった場合、このelseブロックは到達可能になり、neverへの代入はコンパイルエラーとなって設計ミスを検出できます。決して戻らない関数の戻り値としての nevernever型は制御フロー分析の結果として自動的に推論されるだけでなく、関数の戻り値型として明示的に注釈することもできます。never-type.md では、以下の 2 パターンが紹介されています。無限ループconst infiniteLoop (): never { while (true) { // do something } };while (true)のループは決して終了しないため、この関数は値を返すことも、呼び出し元に制御を戻すこともありません。戻り値型neverはその事実を正確に表現しています。例外の投出const throwError (message: string): never { throw new Error(message); };throw文を実行すると関数は中断され、以降のコードは実行されません。throwしか行わない関数の戻り値型はneverとなり、「正常系では呼び出し元に戻ってこない」ことを型で宣言できます。たとえば、以下のように戻り値型の異なる分岐の中で例外関数を呼び出すと、neverはあらゆる型に代入可能neverは bottom typeであるため、TypeScript は矛盾なく型を扱えます。const parseOrThrow (input: string): number { if (input ) { throwError(入力が空です); // ここは決して 戻らない } return Number(input); };ここで重要なのは、neverはあらゆる型に対して代入可能な bottom typeである一方、never以外のどんな型もneverに代入できないという非対称性です。neverへの代入が成立するのは、対象の値が文字通り「存在し得ない」場合に限られます。never 型による網羅性チェックExhaustiveness Checkingnever 型が最も実践的に力を発揮する場面が、網羅性チェックです。判別可能なユニオンdiscriminated unionをswitch文で処理する際、defaultケースの変数をneverとして宣言しておくと、ユニオンのメンバーが追加されたとき未処理のまま放置されるとコンパイルエラーになります。日本語版の章 網羅性チェック では、以下のように定義されています。網羅性チェックは、判別可能なユニオンで取り得るすべてのケースがswitch文またはif文で処理されていることを保証する TypeScript の機能です。典型的な例がこちらです。type Direction up | down; const move (direction: Direction) { switch (direction) { case up: console.log(Moving up); break; case down: console.log(Moving down); break; default: const exhaustiveCheck: never direction; console.log(exhaustiveCheck); // This line will never be executed } };このコードでは、upとdownが両方処理されているため、defaultケースのdirectionはneverに絞り込まれ、const exhaustiveCheck: never direction;は正常にコンパイルされます。ここに新しい値を追加してみましょう。type Direction up | down | left; // left を追加すると、switch文でleftが処理されていないため、defaultケースのdirectionの型はleftのまま残ります。leftはneverに代入できないため、const exhaustiveCheck: never direction;の行でコンパイルエラーが発生します。これにより「ユニオンの拡張時に、対応する分岐を書き忘れる」という典型的なバグを、実行時ではなくコンパイル時に検出できるのです。このパターンは「型安全な最終防衛線」として定番のイディオムです。defaultケースでthrow new Error(...)と組み合わせると、実行時にも安全になります。type Direction up | down; const move (direction: Direction): void { switch (direction) { case up: // move up break; case down: // move down break; default: const exhaustiveCheck: never direction; throw new Error(Unhandled direction: ${exhaustiveCheck}); } };こちらは never-type.md に掲載されている例です。defaultケースでneverに代入しつつ例外を投げることで、コンパイル時の網羅性保証と実行時の不正値防御の両立を実現しています。判別可能なユニオンの基本パターン共通の判別子kindを持つオブジェクトのユニオンについては、discriminated-unions.md を参照してください。never 型の推論を支える絞り込みNarrowingnever 型が自動的に推論される仕組みの背後には、TypeScript の**型の絞り込みnarrowing**があります。narrowing.md によれば、narrowing とは「条件ブロック内で変数の型をより具体的な型へと絞り込む処理」であり、ユニオン型を扱う際に特に有用です。TypeScript が認識する代表的な絞り込み方法には、次のものがあります。絞り込み方法使用例内容typeof型ガードtypeof x number組み込みの JavaScript 型による判定真偽値による絞り込みif (name)truthy / falsy による判定等価性による絞り込みswitch (status)、特定の値との等価比較in演算子による絞り込みbreed in petプロパティの存在有無による判定instanceofによる絞り込みshape instanceof Squareコンストラクタ関数による判定これらを組み合わせてすべての候補を消し去った先に残るのがneverです。冒頭のprintValueの例は、typeof型ガードによる絞り込みを順に適用し、最終的に到達不能なelseブロックでneverを得る典型例です。unknown との併用でさらに強固にunknown-type.md で解説されているように、unknown型は「型が不明な値」を表し、anyと異なり、絞り込みや型アサーションを行うまで操作を一切許可しません。unknown型の値に対して絞り込みを繰り返し、全ケースを網羅した先に到達するneverは、「この値はどの既知の型にも属さない」ことをコンパイラに保証する役割を担います。const add (a: unknown, b: unknown): number | undefined typeof a number typeof b number ? a b : undefined;このように、unknownで受け取って安全な絞り込みを行い、neverで「絶対に発生しないケース」を宣言する、という組み合わせは、厳格な型安全性を求めるコードベースでよく見られる設計です。void との違いに注意never と混同されやすいのがvoid型です。void-type.md によれば、voidは「関数が値を返さないこと」を示します。const sayHello (): void { console.log(Hello!); };voidの関数は「値を返さずに呼び出し元へ制御を戻す」のに対し、neverの関数は「そもそも呼び出し元へ制御を戻さない」無限ループ、例外投出という点で決定的に異なります。関数の戻り値型を設計する際は、この違いを意識しましょう。never 型の実践ガイドラインここまでの内容を踏まえ、never 型を効果的に使うためのポイントをまとめます。到達不能コードの型として利用するtypeofやswitchによる絞り込みを網羅した後のelse/defaultブロックでは、変数をneverとして宣言し、そのブロックが「本当に到達しないこと」をコンパイラに検証させる。決して戻らない関数の戻り値型に注釈する無限ループや必ず例外を投げる関数には(): neverを明示し、関数の挙動を型で宣言する。網羅性チェックのイディオムを使う判別可能なユニオンのswitchでconst exhaustiveCheck: never value;を書き、ユニオン拡張時の未処理ケースをコンパイルエラーとして検出する。voidと混同しないvoidは「戻り値なしで復帰する」、neverは「決して復帰しない」。用途がまったく異なる。特に 3 の網羅性チェックは、状態遷移やコマンド処理など「取り得るケースの集合が後から拡張される」ドメインで真価を発揮します。ユニオンのメンバーが増えた瞬間に、処理を追加し忘れたすべてのswitch文がコンパイルエラーとして浮かび上がるため、安全に機能を拡張できるのです。まとめnever 型は「決して生成されることのない値」を表現する TypeScript 固有の型であり、制御フロー分析による自動推論・決して戻らない関数の戻り値型・網羅性チェックという 3 つの側面から実務で活躍します。the-never-type.md を出発点に、never-type.md や 網羅性チェック の章と併せて読むことで、ユニオン型・絞り込み・判別可能なユニオンといった TypeScript の型システムの核心を体系的に理解できます。関連章として、narrowing.md、discriminated-unions.md、unknown-type.md、void-type.md も合わせて参照すると、never 型が型システム全体の中でどのように位置づけられるかがより明確になるでしょう。赞分享文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载相关推荐claude-howto の /generate-api-docs 徹底解説ソースコードから網羅的 API ドキュメントを自動生成するスラッシュコマンドの全手順claude howto の /generate api docs 徹底解説ソースコードから網羅的 API ドキュメントを自動生成するスラッシュコマンドの全手教程文档es-toolkit の divide 関数完全ガイドLodash 互換の除算ユーティリティをソースコードとテストで徹底解説es toolkit の divide 関数完全ガイドLodash 互換の除算ユーティリティをソースコードとテストで徹底解説 本記事は、es toolkit前端后端『Hello アルゴリズム』スタック・キュー章 総まとめLIFO/FIFO の核心 5 要点と配列・連結リスト実装の比較、章末 QA をソースコードで徹底解説『Hello アルゴリズム』スタック・キュー章 総まとめLIFO/FIFO の核心 5 要点と配列・連結リスト実装の比較、章末 QA をソースコードで徹底解教程文档示例工程教育上一篇终极指南如何用YOLOv11多光谱检测让AI看见看不见的世界下一篇如何在Steam Deck上实现3分钟快速多系统引导SteamDeck_rEFInd完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考