TypeScriptの関数はどのように役立つのか(後編)TypeScriptのTypeあれこれシリーズ(4)

altJS、すなわち、JavaScriptの代わりとなる言語の筆頭である「TypeScript」。TypeScriptという言語名が示す通り、JavaScriptに「Type」、つまり、型の概念を持ち込んだものです。本連載では、このTypeScriptの型に関して、さまざまな方向から紹介していきます。前回は関数の型に関して、基本となる引数や戻り値の型、さらには関数そのものの型を紹介しました。今回は引き続き、関数の型を掘り下げていき、型ガードやオーバーロードなどを紹介します。

» 2022年01月17日 05時00分 公開

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「TypeScriptのTypeあれこれシリーズ」のインデックス

連載:TypeScriptのTypeあれこれシリーズ

ユニオン型引数と型ガード

 連載の第2回では、ユニオン型変数、すなわち、複数のデータ型に対応した変数を紹介しました。このユニオン型は、関数の引数として指定できます。具体例を見ていきましょう。

ユニオン型が引数の関数

 例えば、名前を表す文字列、または、年齢を表す数値という引数を基に、何かメッセージを生成する関数createMessage()があるとします。この関数のシグネチャは、リスト1のようになります。

function createMessage(nameOrAge: string|number): string
リスト1

 このシグネチャのポイントは、引数のデータ型として「string|number」のようにユニオン型を指定したところです。こうすることで、リスト2のように、文字列、数値の両方を渡せるようになりました。

const msg1 = createMessage("田中太郎");
const msg2 = createMessage(25);
リスト2

 一方で、stringとnumber以外のデータ型の引数は渡せません。試しに、boolean型の引数を渡そうとすると、図1のようにエラーになります(以下、「Visual Studio Code」を利用)。

図1 numberかstringを引数とする関数にbooleanを渡してエラーになった画面

データ型を取得できるtypeof演算子

 ここで、リスト2の実行結果として、msg1は「田中太郎さん!ようこそ!」、msg2は「25歳おめでとう!」になるとします。そのようにcreateMessage()関数を作ろうとするならば、当然、引数のデータ型がstringなのかnumberなのか、関数内で分岐させる仕組みが必要になります。その上で、string型なら、引数に「さん!ようこそ!」を追加した文字列を戻り値にします。一方、number型なら、「歳おめでとう!」を追加した文字列にします。

 このように、データ型で分岐する際に活躍する演算子が、「typeof」です。typeofを用いたcreateMessage()関数はリスト3のようになります。

function createMessage(nameOrAge: string|number): string {
	let message = "";
	if(typeof nameOrAge == "string") {  // (1)
		message = `${nameOrAge}さん!ようこそ!`;
	}
	else {  // (2)
		message = `${nameOrAge}歳おめでとう!`;
	}
	return message;
}
リスト3

 リスト3(1)のif条件式の中で、引数nameOrAgeに対してtypeof演算子を適用しています。このtypeof演算子の演算結果は、以下のいずれかの文字列になり、それぞれが該当するデータ型を表します。

string
number
bigint
boolean
symbol
undefined
object
function

 typeofを利用して型判定を行う構文は、次の通りです。

[構文1]typeofによる型判定
typeof 変数 == "データ型文字列"

typeofのifブロック内で型が固定する型ガード

 前項で紹介したtypeof演算子は、TypeScript独自のものではなく、JavaScriptにもあります。しかし、TypeScriptではtypeofに別の利点があります。typeofで型判定を行った条件分岐ブロック内では、該当変数はその型に固定される、という利点です。これを、「型ガード」といいます。

 例えば、リスト3の(1)の条件に合致するブロック内では、nameOrAgeはstring型として振る舞います。そのため、例えば文字数を取得するリスト4のコードは問題なく実行できます。

const length = nameOrAge.length;
リスト4

 一方で、掛け算を実行するリスト5のコードは、型ガードのため、図2のようにエラーになります。

const months = nameOrAge * 12;
リスト5
図2 typeofでstringと判定されたブロック内では変数が文字列として振る舞う

 一方、リスト3(2)のelseブロックでは、nameOrAgeはnumber型として振る舞うので、逆に、リスト4はエラーになり、リスト5は問題なく動作します(図3)。

図3 elseブロック内では数値として振る舞う

 typeofによる型ガードを使うと、引数などで、どうしても複数のデータ型をまとめて扱わなければならない場合でも、安心してコーディングできます。

オブジェクトの型を調べるinstanceof演算子

 ところで、typeof演算子の演算結果を見ると、オブジェクトが全てobject型になってしまいます。オブジェクトの型を区別したい場合は、typeofではなく、「instanceof」演算子を使います。ただし、typeofとは使い方が違います。

 具体例を見てみましょう。例えば、リスト6のようなシグネチャの関数があるとします。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。