SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine(コードジン) DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

ますます便利になるTypeScript! バージョン3からの変更点と総まとめ

TypeScriptバージョン3から5.2までのアップデート内容まとめ ──型の絞り込みについて解説

ますます便利になるTypeScript! バージョン3からの変更点と総まとめ 第4回

制御フロー分析で重要な判別可能なユニオン型

 制御フロー分析の話を進めていくと、登場するのが判別可能なユニオン型という考え方です。

判別可能なユニオン型とは

 前項のリスト5のReturnJSONの考え方をもう少し進めて、リスト7のようなReturnJSONSuccessとReturnJSONFailを定義してみます。これは、サーバ側の処理が成功したか失敗したかで、そのデータ型を別々のインターフェースとしたものです。

リスト7:サーバ側の処理成功と失敗で別々のデータ型としたインターフェース
interface ReturnJSONSuccess {
  status: 1;
  result: string;
}
interface ReturnJSONFail {
  status: 0;
  msg: string;
}

 ここで注目するのは、statusプロパティです。それぞれ、型として1と0が定義されています。これはいわゆるリテラル型であり、しかも、ReturnJSONSuccessでは1、ReturnJSONFailでは0以外の値が格納できないようになっています。このような単一の値の型定義のことを、リテラル型の中でも、特に「ユニット型(Unit Types)」といいます。

 そして、ユニット型が定義された特定のプロパティを共通に持つオブジェクト型のユニオン型を「判別可能なユニオン型(Discriminated Unions)」といいます。例えば、リスト7のReturnJSONSuccessとReturnJSONFailのユニオン型であるReturnJSONを定義し、それを引数の型とする関数showResult()を考えるならば、リスト8のようなコードが成り立ちます。

リスト8:判別可能なユニオン型の制御フロー分析コード
type ReturnJSON = ReturnJSONSuccess | ReturnJSONFail;
function showResult(returnJSON: ReturnJSON) {
  if(returnJSON.status == 0) {  // (1)
    console.log(returnJSON.msg);  // (2)
  }
  else {  // (3)
    console.log(returnJSON.result);  // (4)
  }
}

 リスト8では、(1)と(3)でstatusプロパティの値が0かそれ以外での制御フロー分析を行っています。ReturnJSONSuccess、ReturnJSONFail、および、そのユニオン型であるReturnJSONの型定義のおかげで、returnJSONには必ずstatusプロパティが存在し、しかも、先述のように、その値は、0か1のどちらかであるのが、型定義として保証されているからです。

 さらに、その条件ブロック内では型の絞り込みが行われ、(2)の段階のreturnJSONはReturnJSONFail型、同様に(4)の段階のreturnJSONはReturnJSONSuccess型が保証され、それぞれのプロパティへのアクセスがエラーなく行えます。これが、判別可能なユニオン型の特徴です。

判別可能なユニオン型がユニット型以外でも可能に

 この判別可能なユニオン型の判別を行うプロパティ(リスト8ならばstatus)は、ユニット型である必要がありました。これが、バージョン3.2でユニット型以外もサポートされるようになりました。これにより、例えば、リスト9のような型定義を行い、errorMsgがundefinedかどうか、また、notFoundMsgがundefinedかどうかで、リスト9と同じような制御フロー分析が可能となります。

リスト9:ユニット型以外のプロパティによる判別可能なユニオン型
interface ReturnJSONSuccess {
  errorMsg: undefined;
  notFoundMsg: undefined;
  result: string;
}
interface ReturnJSONFail {
  errorMsg: string;
  notFoundMsg: undefined;
  result: string;
}
interface ReturnJSONNotFound {
  errorMsg: undefined;
  notFoundMsg: string;
  result: string;
}
type ReturnJSON = ReturnJSONSuccess | ReturnJSONFail | ReturnJSONNotFound;

判別可能ユニオン型の分割代入による制御フロー分析

 この判別可能ユニオン型のオブジェクトを分割代入した各変数を用いた制御フロー分析が、バージョン4.6で可能となりました。これを用いると、リスト9のReturnJSON型を引数とする関数showResult()は、リスト10のような制御フロー分析が可能となります。

リスト10:分割代入を利用した判別可能ユニオン型の制御フロー分析
function showResult(returnJSON: ReturnJSON) {
  const {errorMsg, notFoundMsg, result} = returnJSON;
  if(errorMsg != undefined) {
    :
  }
  :
}

タプルを利用した制御フロー分析

 ここまで、判別可能なユニオン型のオブジェクトを利用した制御フロー分析を紹介してきました。この仕組みは、バージョン4.6でタプルでも可能となりました。例えば、リスト11のようなコードです。

リスト11:タプルを利用した制御フロー分析
type ReturnJSONSuccess = [1, string];  // (1)
type ReturnJSONFail = [0, string, string];  // (2)
type ReturnJSONNotFound = [404, string, string];  // (3)
type ReturnJSON = ReturnJSONSuccess | ReturnJSONFail | ReturnJSONNotFound;  // (4)
function showResult(...returnJSON: ReturnJSON) {  // (5)
  if(returnJSON[0] == 0) {  // (6)
    const errorMsg = returnJSON[1];
      :
  }
    :
}

 リスト11の(1)〜(3)では、リスト9のReturnJSONSuccess、ReturnJSONFail、ReturnJSONNotFoundとほぼ同等の働きをするタプルを、同名で定義しています。その第1要素(インデックス0)が、各タプルの判別の元となる値となっています。そして、(4)でこれらのタプルのユニオン型としてReturnJSONを定義し、そのReturnJSONを引数の型とする関数showResult()を定義しています。ただし、その際、...演算子を付与し、残余引数としています。このタプルと残余引数の組み合わせに関しては、第2回を参照してください。

 このような引数returnJSONに対して、(6)では、第1要素の値を判定しており、この判定でもって制御フロー分析と同等の効果が得られます。すなわち、(6)のブロック内では、図5のように、returnJSONはReturnJSONFail型として扱われ、型の絞り込みが行われているのがわかります。

図5:タプルの第1要素で型の絞り込みが行われたreturnJSON
図5:タプルの第1要素で型の絞り込みが行われたreturnJSON

次のページ
アサーション関数

この記事は参考になりましたか?

ますます便利になるTypeScript! バージョン3からの変更点と総まとめ連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。Web系製作会社のシステム部門、SI会社を経てフリーランスとして独立。屋号はSarva(サルヴァ)。HAL大阪の非常勤講師を兼務。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/19331 2024/04/19 11:00

おすすめ

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー