WEBVTT

1
00:00:00.000 --> 00:00:00.990
こんにちは。

2
00:00:00.990 --> 00:00:05.608
タイプスクリプト入門、第六回はユニオン型と型ガードです。

3
00:00:05.608 --> 00:00:07.917
前回は関数の型を学びました。

4
00:00:07.917 --> 00:00:14.019
今回は、一つの値が複数の型を取り得る場合に、型を安全に扱う方法を学びます。

5
00:00:14.019 --> 00:00:15.834
キーワードは三つです。

6
00:00:15.834 --> 00:00:23.256
候補を列挙するユニオン型、候補を減らす絞り込み、そして絞り込みの仕組みである型ガードです。

7
00:00:23.256 --> 00:00:28.699
さらに、外部から届いた不明な値を検証する方法と、処理漏れをコンパイル時に見つけるネバーの使い方まで、

8
00:00:28.699 --> 00:00:34.141
配送状態を題材に順に確認します。

9
00:00:34.141 --> 00:00:41.893
この回を終えるころには、状態ごとに必要なデータが違うデータを、型で安全に表せるようになります。

10
00:00:41.893 --> 00:00:50.140
型は実行時には残りませんが、書いている最中とコンパイルの段階で、間違いを早く見つける助けになります。

11
00:00:50.140 --> 00:00:51.712
まずユニオン型です。

12
00:00:51.712 --> 00:00:56.584
ユニオン型は、値が取り得る型を縦棒でつないで列挙したものです。

13
00:00:56.584 --> 00:01:01.771
たとえば文字列か数値、という変数は、文字列と数値のどちらも代入できますが、

14
00:01:01.771 --> 00:01:06.958
それ以外の真偽値などを入れようとすると型エラーになります。

15
00:01:06.958 --> 00:01:14.345
大切なのは、ユニオン型の値には、すべての候補に共通する操作しか、そのままでは使えないことです。

16
00:01:14.345 --> 00:01:18.588
文字列専用のメソッドを呼ぼうとするとエラーになります。

17
00:01:18.588 --> 00:01:27.076
何でも許すエニー型に変えてしまえばエラーは消えますが、存在しないメソッドを呼ぶ誤りも見つけられなくなります。

18
00:01:27.076 --> 00:01:30.848
候補を絞ってから使う、というのが基本の流れです。

19
00:01:30.848 --> 00:01:35.110
候補を絞る代表的な方法が、タイプオブによる判定です。

20
00:01:35.110 --> 00:01:38.388
参照番号を整形する関数で見てみましょう。

21
00:01:38.388 --> 00:01:42.814
この関数は、文字列か数値を受け取り、文字列を返します。

22
00:01:42.814 --> 00:01:49.370
タイプオブで数値かどうかを判定し、数値なら数値専用のメソッドで丸めて表示します。

23
00:01:49.370 --> 00:01:54.616
そうでなければ、文字列として空白を取り除き、大文字に変換します。

24
00:01:54.616 --> 00:02:02.484
呼び出し結果は、数値の四十二がナンバー四十二、空白付きの文字列が大文字に整えられて表示されます。

25
00:02:02.484 --> 00:02:08.057
判定の中でだけ、その型専用の操作が安全に使える点に注目してください。

26
00:02:08.057 --> 00:02:13.138
なお、数値であることは、業務上正しい番号であることとは別です。

27
00:02:13.138 --> 00:02:16.908
必要なら整数かどうかなどを別途検証しましょう。

28
00:02:16.908 --> 00:02:22.437
このように、判定や処理の流れから型の候補を減らすことを、型の絞り込みと呼びます。

29
00:02:22.437 --> 00:02:25.340
ポイントは、早期にリターンする書き方です。

30
00:02:25.340 --> 00:02:32.251
数値の分岐でリターンした後は、その先のコードでは数値の可能性が消え、残る候補は文字列だけになります。

31
00:02:32.251 --> 00:02:36.398
コンパイラはこの流れを追って、候補を自動で減らしてくれます。

32
00:02:36.398 --> 00:02:41.651
そして、タイプオブのように型を判定する仕組みそのものを、型ガードと呼びます。

33
00:02:41.651 --> 00:02:46.766
等しいかどうかの比較や、値があるかどうかの確認も、絞り込みとして働きます。

34
00:02:46.766 --> 00:02:51.880
絞り込みは特別な記法ではなく、普段の条件分岐の中で起きていることなのです。

35
00:02:51.880 --> 00:02:55.621
次に、状態とデータを組み合わせる方法です。

36
00:02:55.621 --> 00:03:01.232
配送の状態を、単なる文字列と、任意の宛先やエラー文で表すと、配送成功なのに宛先がない、

37
00:03:01.232 --> 00:03:06.843
という矛盾したデータも作れてしまいます。

38
00:03:06.843 --> 00:03:10.940
そこで、状態ごとにオブジェクトの形を分けます。

39
00:03:10.940 --> 00:03:18.243
配送待ちには追加のデータはなし、送信済みには宛先が必須、失敗には理由が必須、

40
00:03:18.243 --> 00:03:25.546
という三つの形を用意し、共通のステータスには、それぞれ異なる文字列リテラルを指定します。

41
00:03:25.546 --> 00:03:33.205
このように、判別に使う共通プロパティを持つユニオン型を、判別可能なユニオンと呼びます。

42
00:03:33.205 --> 00:03:38.727
状態と必要なデータを、型のレベルで結び付けられるのが利点です。

43
00:03:38.727 --> 00:03:45.140
この形なら、コンパイラが状態とデータの正しい組み合わせを覚えてくれます。

44
00:03:45.140 --> 00:03:49.697
判別可能なユニオンは、スイッチ文と相性がよい書き方です。

45
00:03:49.697 --> 00:03:56.533
ステータスで分岐すると、各分岐の中では、その状態のオブジェクトだけが候補に残ります。

46
00:03:56.533 --> 00:04:02.718
送信済みの分岐では宛先を、失敗の分岐では理由を、そのまま安全に読み取れます。

47
00:04:02.718 --> 00:04:08.414
逆に、別の状態のプロパティを無条件に読もうとすると型エラーになります。

48
00:04:08.414 --> 00:04:13.460
状態とデータの取り違えを、コンパイル時に見つけられるわけです。

49
00:04:13.460 --> 00:04:16.227
表示の文言は状態ごとに決まります。

50
00:04:16.227 --> 00:04:20.621
配送待ち、宛先付きの配送完了、理由付きの配送失敗です。

51
00:04:20.621 --> 00:04:25.992
分岐を書く側も読む側も、今どの状態を扱っているかが明確になります。

52
00:04:25.992 --> 00:04:31.027
すべての状態を処理した後のデフォルト分岐には、残る候補がありません。

53
00:04:31.027 --> 00:04:34.434
その、値が存在しないことを表す型がネバーです。

54
00:04:34.434 --> 00:04:36.951
この性質を網羅チェックに使います。

55
00:04:36.951 --> 00:04:41.394
デフォルトでは、ネバー型の引数だけを受け取る関数を呼びます。

56
00:04:41.394 --> 00:04:47.244
もし新しい状態、たとえば再試行中を追加したのに分岐を足し忘れると、デフォルトにその状態が残ってしまい、

57
00:04:47.244 --> 00:04:53.094
ネバーを期待する場所に渡せなくなって型エラーになります。

58
00:04:53.094 --> 00:04:58.425
つまり、処理漏れを実行前にコンパイルエラーとして教えてくれる仕組みです。

59
00:04:58.425 --> 00:05:02.572
状態を増やすときの安全網として、ぜひ覚えておきましょう。

60
00:05:02.572 --> 00:05:08.434
外部から届いた値は、型が不明なアンノウンとして受け取るのが安全です。

61
00:05:08.434 --> 00:05:12.917
そのままでは使えないため、検証してから型を付けます。

62
00:05:12.917 --> 00:05:16.020
ここで使うのが、独自の型ガードです。

63
00:05:16.020 --> 00:05:24.123
戻り値の型に型述語を書くと、真を返したときに、その値が宣言した型であるものとして絞り込めます。

64
00:05:24.123 --> 00:05:30.761
配送状態の検証では、まずオブジェクトであることとヌルでないことを確かめ、

65
00:05:30.761 --> 00:05:37.399
ステータスがあるかを確認し、状態ごとに必要な項目が文字列で存在するかまで調べます。

66
00:05:37.399 --> 00:05:41.709
ただし型述語は、実装が正しいという前提で動きます。

67
00:05:41.709 --> 00:05:49.640
検証の書き間違いはコンパイラには証明できないため、不足した項目やヌルなどのテストも必要です。

68
00:05:49.640 --> 00:05:52.771
では、実際に動かして確かめましょう。

69
00:05:52.771 --> 00:05:59.555
不明な値の配列に、正しい三つの状態と、宛先が欠けたデータと、ヌルを用意します。

70
00:05:59.555 --> 00:06:05.644
一つずつ検証し、配送状態として認められたものだけを表示関数に渡します。

71
00:06:05.644 --> 00:06:11.471
結果は、配送待ち、宛先付きの配送完了、理由付きの配送失敗の順に表示され、

72
00:06:11.471 --> 00:06:17.299
宛先が欠けたデータとヌルは、不正な配送状態として拒否されます。

73
00:06:17.299 --> 00:06:22.517
ここで、型を断定するアズだけでは、この検証は実行されません。

74
00:06:22.517 --> 00:06:28.953
断定はコンパイラへの言い切りであり、実行時のチェックにはならないからです。

75
00:06:28.953 --> 00:06:33.128
検証を通った値だけが、安全な表示処理へ進めます。

76
00:06:33.128 --> 00:06:41.652
コンパイルはストリクトを有効にして行い、生成されたジャバスクリプトをノードで実行して確認しました。

77
00:06:41.652 --> 00:06:44.382
よくある落とし穴も押さえておきましょう。

78
00:06:44.382 --> 00:06:49.434
第一に、値そのもので判定すると、空文字やゼロも一緒に除外されてしまいます。

79
00:06:49.434 --> 00:06:54.758
値がない場合だけを除きたいなら、ヌルとアンディファインドを明示的に判定します。

80
00:06:54.758 --> 00:06:58.171
第二に、ヌルのタイプオブはオブジェクトになります。

81
00:06:58.171 --> 00:07:01.720
プロパティに触れる前に、ヌルを先に除外してください。

82
00:07:01.720 --> 00:07:05.406
第三に、イン演算子は継承したプロパティにも反応します。

83
00:07:05.406 --> 00:07:11.277
形の確認と、自分のプロパティだけを許可する厳密な検証は、目的が違う点に注意しましょう。

84
00:07:11.277 --> 00:07:17.830
そして、非ヌルアサーションで警告だけを消すと、値がない場合の扱いという判断がコードに残りません。

85
00:07:17.830 --> 00:07:20.560
決めた扱いを、コードとして書きましょう。

86
00:07:20.560 --> 00:07:21.511
まとめです。

87
00:07:21.511 --> 00:07:29.754
ユニオン型は候補を縦棒で列挙し、各候補に固有の操作は、タイプオブなどの型ガードで絞り込んでから使います。

88
00:07:29.754 --> 00:07:37.362
判別可能なユニオンでは、状態ごとに必要なデータを結び付け、スイッチの各分岐で安全に読み取れます。

89
00:07:37.362 --> 00:07:45.605
すべての分岐を処理した後に残るネバーを使えば、新しい状態の処理漏れをコンパイルエラーとして検出できます。

90
00:07:45.605 --> 00:07:51.152
外部入力はアンノウンで受け取り、型述語を持つ検証を通してから使います。

91
00:07:51.152 --> 00:07:56.066
型による確認と、実行時の検証は別のものだという区別も大切です。

92
00:07:56.066 --> 00:07:59.553
次回は第七回として、ジェネリクスを学びます。

93
00:07:59.553 --> 00:08:00.980
お疲れさまでした。
