HTML5テクニカルノート
TypeScriptハンドブック 03: ユニオン型
- ID: FN2104003
- Technique: ECMAScript 2015
- Package: TypeScript 4.2
「TypeScriptハンドブック」シリーズ第3回で採り上げるのは、「Everyday Types」のページから、つぎのとおりユニオン型です(かっこ内は原文の項目タイトル)。TypeScriptでは、すでにある型からさまざまな演算子を用いて、新たな型がつくれます。ユニオン型(演算子|
)は、その中のひとつです。
01 ユニオン型
ユニオン型(union type)は、共用体型と呼ばれることもあります。複数の型を演算子|
で結び、そのうちのいずれかひとつを示す型です。演算子|
で結ばれたそれぞれの型を、ユニオンのメンバーといいます。
01-01 ユニオン型を定める
つぎの関数(printId()
)は、引数(id
)をnumber
とstring
のユニオン型としました。引数に渡せるのは、数値か文字列だけです。それ以外の値は受け取りません。
function printId(id: number | string) { console.log("Your ID is: " + id); } printId(101); // Your ID is: 101 printId("202"); // Your ID is: 202 // 型 'string[]' の引数を型 'string | number' のパラメーターに割り当てることはできません。 // 型 'string[]' を型 'string' に割り当てることはできません。 // printId(["202"]);
ノート01■数値の配列を渡したときのエラー
前掲の関数(printId()
)に、数値の配列を渡したとき、エディタ(Visual Studio Code)に示されるエラーが正しくないようです。
// 型 'number' を型 'string' に割り当てることはできません。 printId([303]);
それでも実行すすれば、コンソールには正しいエラーメッセージが表れます。
Argument of type 'number[]' is not assignable to parameter of type 'string | number'. Type 'number[]' is not assignable to type 'string'.
01-02 ユニオン型を使う
ユニオン型は、メンバーのいずれかの型と合致すれば、値を受け取ります。では、ユニオン型の値を使うときはどうでしょう。前掲の関数(printId()
)を書き替え、引数(id
)に対してString
オブジェクトのメソッド(String.prototype.substr()
)を呼び出そうとしたのが以下のコードです。
ユニオン型の値そのままのとき、TypeScriptはすべてのメンバーが備えるプロパティやメソッドの参照しか許しません。そのため、ユニオン型string | number
の値に、number
がもたないメソッドは呼び出せないのです。
function printId(id: number | string) { // プロパティ 'substr' は型 'string | number' に存在しません。 // プロパティ 'substr' は型 'number' に存在しません。 console.log("Your ID is: " + id.substr(-2)); }
こういうときは、コードで論理的に値を絞り込みます。TypeScriptはその論理構造にしたがって、値の型をより具体的に推論するのです。
今回のユニオン型であれば、typeof
演算子でstring
の場合をif
文により切り分けられます。すると、切り分けた処理の中では、TypeScriptは値をstring
型として扱うことになるのです。これは、型づけのない標準JavaScriptでも行っていることでしょう。 また、number | string
のユニオン型でstring
を切り分けたのですから、else
文の値はTypeScriptがnumber
とみなします。
function printId(id: number | string) { if (typeof id === "string") { console.log("Your ID is: " + id.substr(-2)); } else { console.log("Your ID is: " + id % 100); } } printId(101); // Your ID is: 1 printId("202"); // Your ID is: 02
関数の引数に、ひとつの型とその配列を受け取らせたいときも、ユニオン型で表せます。つぎの関数(welcomePeople()
)の引数(names
)は、string[]
とstring
のユニオン型です。ふたつの切り分けには、Array.isArray()
メソッドを用いればよいでしょう。
function welcomePeople(names: string[] | string) { if (Array.isArray(names)) { console.log("Hello, " + names.join(" and ")); } else { console.log("Welcome lone traveler " + names); } } welcomePeople(["Alice", "Bob", "Eve"]); // Hello, Alice and Bob and Eve welcomePeople("Alice"); // Welcome lone traveler Alice
ユニオン型の複数のメンバーが、たまたま同じプロパティやメソッドを備えている場合もあるでしょう。その場合は、値の切り分けはしなくて構いません。たとえば、つぎの関数(getFirstThree()
)は、引数(x
)の配列と文字列に共通するプロパティとメソッドを参照した例です。
function getFirstThree(x: number[] | string) { return {firstThree: x.slice(0, 3), length: x.length}; } console.log(getFirstThree([0, 1, 2, 3, 4])); // {firstThree: [0, 1, 2], length: 5} console.log(getFirstThree("01234")); // {firstThree: "012", length: 5}
作成者: 野中文雄
作成日: 2021年04月17日
Copyright © 2001-2020 Fumio Nonaka. All rights reserved.