プリミティブ型 (Primitive types)

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

プリミティブ型とは

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

振る舞いがないとは

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

null.toString();

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

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

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

undefined

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

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

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

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

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

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

歴史的背景

以前はグローバルスコープの変数だったため上書きができました。そのため、その値がundefinedであるかどうかの判定に対してundefiniedとの等値比較をすることが必ずしも正しくないことがありました。昨今の環境ではundefinedは代入ができないプロパティとして設定されているため簡便にundefinedとの等値比較をすることでその値がundefinedかどうかの判定ができます。

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

古い環境で動作することを考慮する必要がある時や、かつての正しい判定を使いたい時はtypeofを使います。

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

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

undefined = void 0;

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

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

TypeScriptの型としてのundefined

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

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

null

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

undefinedと異なりこちらはリテラルであり、上書きされる危険は考慮する必要がありません。等値比較もnullとの比較で問題ありません。かえってtypeofnullを判定させると'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型の変数を作成したい時は'(single quote)"(double quote)のどちらかを使います。TypeScriptではこれらの差はありません。開始時の記号と終了時の記号が合っている必要と、途中にその文字が含まれている場合はエスケープされている必要があります。

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

テンプレートリテラル

', "ではなく`(back tick)で囲むとテンプレートリテラルという文字列を作ることができます。テンプレートリテラルは', "で宣言されているstring型と異なり

  • 改行できる

  • 変数展開できる

という利点があります。

改行できる

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

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

変数展開できる

今までは+を使って調整していた文字列に、直感的に変数を代入できるようになりました。SQLのような制御構文を書いていると、'"がJSの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型の名前を与え、そのsymbolを外部に露出させないことで擬似的なprivateプロパティ、メソッドを実現していました。

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

メソッドの表記が不思議に見えますが[sym]()symbol型を使ったメソッド表記です。このメソッドにアクセスするために必要な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.jsontargetes2020以上の時に限られます。 それ以外のtargetではBigInt()の関数を使ってbigint型を作り出す必要があります。tsconfig.jsonの話は該当ページをご覧ください。

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