プリミティブ型 (Primitive Types)

TypeScriptはJavaScriptの機能を独自拡張しているわけではないため、JavaScriptにあるプリミティブ型をそのまま使うことができます。

プリミティブ型とは

プリミティブ自体の意味は「単純である、シンプル」に近くただその値のみに意味があることを示しています。そのためプリミティブ型は一般的には振る舞いを持ちません。

振る舞いがないとは

振る舞いがないとはメソッドを持たないことです。

null.toString();

意図せずこのようにしてしまい実行時エラーになってしまった経験はあるかと思います。これはnulltoString()という振る舞いを持っていないことに起因します。

とはいうもののJavaScriptにおいてプリミティブ型の多くはラッパークラスを持っています。ラッパークラスを持つプリミティブ型の値はメソッド呼び出しがあれば実行時に、対応するラッパークラスのインスタンスに変換されるため、あたかもプリミティブ型が振る舞いを持つように見え、またそのように使うことができます。これはJavaを使われている方にとってはおなじみのAutoboxingというJavaScriptの言語機能です。

以下はJavaScriptに用意されているプリミティブ型の紹介です。

undefined

値がないことを示す値です。他言語のnullのように設定されなかったときに代入されます。

存在しないプロパティへのアクセス

オブジェクトに存在しないプロパティにアクセスしたときはundefinedが返却されます。

const str: any = 90;
str.length;
// -> undefined

JavaScriptでは配列はnumber型のプロパティを持つオブジェクトと解釈されているため、存在しないインデックスのアクセスも同様にundefinedが返却されます。

const fruits: string[] = ['Apple', 'Papaya', 'Tomato'];
fruits[7800000];
// -> undefined

歴史的背景

以前はグローバルスコープの変数だったため上書きができました。そのためその値がundefinedであるかどうかの判定に対してundefinedとの等値比較をすることが必ずしも正しくないことがありました。

昨今の環境においてはundefinedは代入ができないプロパティとして設定されているためundefinedとの等値比較をすることでその値がundefinedかどうかの判定ができますが、古い環境で動作することも保証する必要がある時はtypeofを使います。

if (whatIsThis === undefined) {
// whatIsThis is undefined
}
if (typeof whatIsThis === 'undefined') {
// whatIsThis is undefined
}

もしもundefinedが別の値で上書きされた時はvoid演算子を使うことでundefinedの戻り値を得ることができます。このときvoidの右にある式にこだわりはなくどのような式でも構いません。多くの資料でvoid 0となっていることを確認できると思います。

undefined = void 0;

これを等値比較に使うこともできます。

if (whatIsThis === void 0) {
// whatIsThis is undefined
}

型としてのundefined

TypeScriptには型にundefined型が用意されていますがそれとは別にvoid型(これは上記演算子とは異なり、型です)も用意されています。戻り値の型として使う場合はvoid型の方がよく見られ、また望ましい場合が多いです。こちらの解説は関数のページをご覧ください。

ラッパークラスはありません。

null

値がないことを示す値です。他言語のnullのような役割はundefinedが担っていることが多く、こちらは意図的に値を指定しないことを強調できます。

undefinedと異なりこちらはリテラルであり、上書きされる危険を考慮する必要がありません。等値比較もnullとの比較で問題ありません。かえってtypeofを使うと戻り値が'object'となってしまいます。

typeof null;
// -> 'object'

ラッパークラスはありません。

boolean

真偽値と呼ばれる2値のみを持ちます。ラッパークラスはBooleanです。

number

整数だけではなく実数を含めた数値を扱います。四則演算+, -, *, /に加え剰余%と累乗**ができます。

メソッド呼び出し

数値リテラルに対し直接メソッド呼び出しをしたい場合は小数点とメソッドアクセスに使われる記号.が同じため注意が必要です。厳密には整数部しか持たない数値リテラルのときは.がふたつ必要です。

5..toString();
// -> '5'
6.08.toString();
// -> '6.08'

2進数、8進数、16進数

10進数だけではなく2進数、8進数、16進数の表記も可能です。それぞれ表現したい数値の前に0b, 0o, 0xをつけます。

0b1;
0o1;
0x1;

Numeric Separator

視認性を上げるために数値を_で区切ることができます。n桁ずつ区切るなどといった決まりはなく、国や地域の慣習で自由に選択できます。

const million: number = 10_000_00_0_00.0_000000_00;

しかしながら_を先頭や末尾、小数点の前後に置いたり、連続で2個以上置くことはできません。つまり次のような表記はできません。

_100;
100_;
100_.0;
100._0;
1__00;

特殊な値

Infinity, -Infinity, NaNという特殊な値を持っています。これらはリテラル型として使うことができません。

NaNはいかなる値と等値比較してもfalseとなる特殊な値で、その値がNaNであるかを判定したい時はこの性質を逆に利用します。

function isNaN(n: number): boolean {
return n !== n;
}

ラッパークラスはNumberです。

string

0文字以上の文字からなる文字列を扱います。number型と文字は同じですが意味の異なる連結+の演算子を処理できます。

演算子の+

string型同士であれば単純で、ただの文字列の合成を意味します。

const w1: string = 'World';
const w2: string = 'Wide';
const w3: string = 'Web';
console.log(w1 + w2 + w3);
// -> 'WorldWideWeb'

string型の変数を定義したい時はシングルクォート'かダブルクォート"のどちらかを使います。TypeScriptではこれらの差はありません。開始時の記号と終了時の記号が合っている必要と、途中にその文字が含まれている場合はバックスラッシュ\でエスケープされている必要があります。

const palindrome1: string = 'madam, I\'m Adam.';
const palindrome2: string = "madam, I'm Adam.";

テンプレートリテラル(テンプレートリテラル)

バッククォート```````で囲むとテンプレートリテラルという文字列を作ることができます。テンプレートリテラルは'""で宣言されるstring`型と異なり

  • 改行できる

  • 変数展開できる

という利点があります。

改行できる

テンプレートリテラルが導入されるまでは上のようにしなければいけなかった文字列が下のように書けるようになりました。

console.log(' _ _ _');;
console.log(' (_)(_) | |');
console.log(' __ _ ___ ___ _ _ ______ __ _ _ __ | |_');
console.log(' / _` |/ __| / __|| || ||______| / _` || \'__|| __|');
console.log(' | (_| |\\__ \\| (__ | || | | (_| || | | |_');
console.log(' \\__,_||___/ \\___||_||_| \\__,_||_| \\__|');
console.log(` _ _ _
(_)(_) | |
__ _ ___ ___ _ _ ______ __ _ _ __ | |_
/ _\` |/ __| / __|| || ||______| / _\` || '__|| __|
| (_| |\\__ \\| (__ | || | | (_| || | | |_
\\__,_||___/ \\___||_||_| \\__,_||_| \\__|`);

変数展開できる

今までは+を使って調整していた文字列に、直感的に変数を代入できるようになりました。SQLのような制御構文を書いていると'"がJavaScriptのstring型の開始、終了の文字なのかそれとも制御文の開始、終了なのかで非常に混乱するため、この変数展開で簡潔にかけるのは便利です。

const prefecture: string = 'Tokyo';
const paid: boolean = true;
const select1: string = 'SELECT * FROM customers JOIN users ON customers.user_id = users.user_id WHERE user.residence = "' + prefecture + '" AND user.paid = ' + paid + ';';
const select2: string = `SELECT *
FROM customers
JOIN users
ON customers.user_id = users.user_id
WHERE user.residence = "${prefecture}"
AND user.paid = ${paid};`;

(注意) これは例です。実際にはSQLのクエリをこのようにして作成せず、プリペアドステートメントを使用してください。

ラッパークラスはStringです。

symbol

symbolはその値のみが一意になるように設計されているプリミティブ型です。boolean, number, string型は同じリテラルであれば等値比較がtrueになりますがsymbolは必ず同じものでない限りtrueにはなりません。この性質はリファレンス型の等値比較に似ています。

const sym1: symbol = Symbol('Dove is a symbol of peace');
const sym2: symbol = Symbol('Dove is a symbol of peace');
console.log(sym1 === sym1);
// -> true
console.log(sym1 === sym2);
// -> false

Symbol()symbol型を返す関数ですが、ここに引数として同じ値を与えても同じsymbolを得ることはできません。

また見た目からnew Symbol()としがちですがSymbol()はコンストラクタではないためこのように書くことはできません。

symbolの使い方

symbol型はその一意性のために使われます。かつてJavaScriptはクラスのプロパティ、メソッドに対して可視性を与えることができませんでした。つまり外部からアクセスしてほしくないプロパティ、メソッドがあってもそれを隠蔽、保護する手段がありませんでした。

そのような外部からアクセスしてほしくないメソッドに対してsymbol型の名前を与え、その値を外部に露出させないことで疑似的なprivateプロパティ、メソッドを実現していました。

const sym = Symbol();
class Sample {
exposedMethod() {
const secret = this[sym]();
// ...
return value;
}
[sym]() {
return 'super secret data';
}
}
module.exports = {
Sample
};

メソッドの表記が不思議に見えますが[sym]()symbol型を使ったメソッド表記です。このメソッドにアクセスするために必要な変数symはこのjsファイルから露出していないため、外部からは見ることができません。

ラッパークラスはSymbolです。

bigint

number型よりも大きな整数を扱います。number型と同じように四則演算+, -, *, /に加え剰余%と累乗**ができます。

宣言

number型と同様に数値リテラルを書くだけではなく、末尾にnをつけます。

const bg1: bigint = 100n;

またはBigInt()を使います。このときBigint()ではない(Intは大文字から始まります)ことに注意してください。

const bg2: bigint = BigInt(100);

演算

number型と一緒に演算をすることはできません。どちらかに型を合わせる必要があります。

2n + 3;
// Operator '+' cannot be applied to types '2n' and '3'.

number型が小数部を持っていない限り、より表現幅の広いbigint型に合わせる方が無難です。

2n + BigInt(3);
// -> 5n

es2020以前の場合

宣言においてbigint型はnumber型の宣言方法の末尾にnをつけるだけで宣言ができるように書いていますがこれは tsconfig.json の targetes2020以上のときに限られます。 それ以外のtargetではBigInt()の関数を使ってbigint型を作り出す必要があります。tsconfig.jsonの話は該当ページをご覧ください。

ラッパークラスはBigIntです。こちらもIntが大文字になることに注意してください。