基本的なデータ型
この章では、TypeScriptの基本的なデータ型について学びます。
この章で学ぶこと
- number、string、boolean型の使い方
- 配列型(
Array<T>とT[])の書き方と操作 - タプル型の特徴と活用方法
- 型推論と型注釈の使い分け
この章では、TypeScript Playgroundまたは前章で構築したローカル環境を使って、コードを書きながら学習を進めましょう。
number型(数値)
JavaScriptと同様、TypeScriptの数値はすべてnumber型です。整数と浮動小数点数の区別はありません。
// 整数
let integer: number = 42;
let negative: number = -10;
// 浮動小数点数
let decimal: number = 3.14;
let scientific: number = 1.5e10; // 1.5 × 10^10 = 15000000000
// 2進数、8進数、16進数
let binary: number = 0b1010; // 2進数: 10
let octal: number = 0o744; // 8進数: 484
let hex: number = 0xff; // 16進数: 255
// 特殊な数値
let infinity: number = Infinity;
let negInfinity: number = -Infinity;
let notANumber: number = NaN;
数値セパレータ
大きな数値を読みやすくするために、アンダースコア(_)を区切り文字として使えます。
// 数値セパレータの使用例
let million: number = 1_000_000; // 1000000
let billion: number = 1_000_000_000; // 1000000000
let creditCard: number = 1234_5678_9012_3456;
// コンパイル後のJavaScriptではセパレータは削除される
console.log(million); // 1000000
数値の演算
let a: number = 10;
let b: number = 3;
console.log(a + b); // 13 (加算)
console.log(a - b); // 7 (減算)
console.log(a * b); // 30 (乗算)
console.log(a / b); // 3.333... (除算)
console.log(a % b); // 1 (剰余)
console.log(a ** b); // 1000 (べき乗: 10^3)
string型(文字列)
文字列は3種類の方法で表現できます。
// シングルクォート
let single: string = 'Hello';
// ダブルクォート
let double: string = "World";
// テンプレートリテラル(バッククォート)
let template: string = `Hello, World!`;
テンプレートリテラルの活用
テンプレートリテラルを使うと、変数や式を文字列に埋め込めます。
let name: string = 'Alice';
let age: number = 25;
// 変数の埋め込み
let message: string = `My name is ${name} and I am ${age} years old.`;
console.log(message);
// 出力: My name is Alice and I am 25 years old.
// 式の埋め込み
let price: number = 100;
let taxRate: number = 0.1;
let total: string = `合計: ${price * (1 + taxRate)}円`;
console.log(total);
// 出力: 合計: 110.00000000000001円
// (0.1 は 2 進数の浮動小数点で正確に表現できないため誤差が出る)
// 複数行の文字列(改行が保持される)
let poem: string = `
Roses are red,
Violets are blue,
TypeScript is awesome,
And so are you!
`;
文字列結合との比較
// 従来の文字列結合(読みにくい)
let oldStyle: string = 'My name is ' + name + ' and I am ' + age + ' years old.';
// テンプレートリテラル(読みやすい)
let newStyle: string = `My name is ${name} and I am ${age} years old.`;
boolean型(真偽値)
真(true)または偽(false)の2つの値のみを持つ型です。
// 基本的な使い方
let isActive: boolean = true;
let isCompleted: boolean = false;
// 比較演算の結果
let age: number = 20;
let isAdult: boolean = age >= 18; // true
let isEqual: boolean = (10 === 10); // true
let isGreater: boolean = (5 > 10); // false
// 論理演算
let a: boolean = true;
let b: boolean = false;
console.log(a && b); // false (AND: 両方trueの時だけtrue)
console.log(a || b); // true (OR: どちらかがtrueならtrue)
console.log(!a); // false (NOT: 真偽値を反転)
実践的な使用例
// ユーザーの状態管理
let isLoggedIn: boolean = false;
let hasPermission: boolean = true;
let isAdmin: boolean = false;
// 条件分岐
if (isLoggedIn && hasPermission) {
console.log('Access granted');
} else {
console.log('Access denied');
}
// デバッグフラグ
let debugMode: boolean = true;
if (debugMode) {
console.log('Debug information: ....');
}
JavaScriptのTruthy/Falsyはboolean型とは異なります。1や"true"はboolean型ではありません。
型注釈と型推論
TypeScriptには、型を自動的に推論する機能があります。
// パターン1: 型注釈を明示的に書く
let message: string = 'Hello';
let count: number = 10;
let isActive: boolean = true;
// パターン2: 型推論に任せる(推奨)
let message2 = 'Hello'; // string型と推論される
let count2 = 10; // number型と推論される
let isActive2 = true; // boolean型と推論される
型注釈が必要なケース
// ケース1: 初期値を設定しない場合
let username: string; // 型注釈が必要
username = 'John'; // 後で値を代入
// ケース2: 型推論では不十分な場合
let data: string | null = null; // 複数の型を許容する場合
ベストプラクティス
// 良い例: 初期値があれば型推論に任せる
let message = 'Hello';
let count = 0;
// 良い例: 初期値がない場合は型注釈を書く
let username: string;
let age: number;
// 冗長な例: 型推論で十分なのに型注釈を書いている
let message: string = 'Hello'; // 型推論で十分
配列型
配列は同じ型の値を複数格納できるデータ構造です。
配列の宣言方法
// 方法1: 型[]構文(推奨)
let numbers: number[] = [1, 2, 3, 4, 5];
let names: string[] = ['Alice', 'Bob', 'Charlie'];
let flags: boolean[] = [true, false, true];
// 方法2: Array<型>構文(ジェネリック構文)
let numbers2: Array<number> = [1, 2, 3, 4, 5];
let names2: Array<string> = ['Alice', 'Bob', 'Charlie'];
// 型推論を活用
let numbers3 = [1, 2, 3, 4, 5]; // number[] と推論
let names3 = ['Alice', 'Bob']; // string[] と推論
let mixed = [1, 'two', true]; // (string | number | boolean)[] と推論
配列の操作
let fruits: string[] = ['apple', 'banana', 'orange'];
// 要素へのアクセス(インデックスは0から始まる)
console.log(fruits[0]); // 'apple'
console.log(fruits[1]); // 'banana'
console.log(fruits[2]); // 'orange'
// 要素の変更
fruits[1] = 'grape';
console.log(fruits); // ['apple', 'grape', 'orange']
// 配列の長さを取得
console.log(fruits.length); // 3
// 要素の追加
fruits.push('melon'); // 末尾に追加
console.log(fruits); // ['apple', 'grape', 'orange', 'melon']
// 要素の削除
let lastFruit = fruits.pop(); // 末尾を削除して返す
console.log(lastFruit); // 'melon'
配列のメソッド
let numbers: number[] = [1, 2, 3, 4, 5];
// map: 各要素を変換した新しい配列を作成
let doubled: number[] = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter: 条件を満たす要素だけの新しい配列を作成
let evens: number[] = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]
// reduce: 配列の要素を集約して1つの値にする
let sum: number = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15 (1+2+3+4+5)
// find: 条件を満たす最初の要素を取得
let found: number | undefined = numbers.find(n => n > 3);
console.log(found); // 4
// includes: 配列に特定の値が含まれているか確認
let hasThree: boolean = numbers.includes(3);
console.log(hasThree); // true
型安全性の例
let numbers: number[] = [1, 2, 3];
// OK: number型の値を追加
numbers.push(4);
// Error: string型の値は追加できない
// numbers.push('5');
// Error: Argument of type 'string' is not assignable to parameter of type 'number'
多次元配列
// 2次元配列(行列のイメージ)
let matrix: number[][] = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
// 要素へのアクセス
console.log(matrix[0][0]); // 1 (1行1列)
console.log(matrix[1][1]); // 5 (2行2列)
console.log(matrix[2][2]); // 9 (3行3列)
読み取り専用配列
変更できない配列を作成する場合はreadonly修飾子を使います。
// readonly配列の宣言
let numbers: readonly number[] = [1, 2, 3, 4, 5];
// 読み取りはOK
console.log(numbers[0]); // 1
console.log(numbers.length); // 5
// 変更しようとするとエラー
// numbers[0] = 10; // Error
// numbers.push(6); // Error
// numbers.pop(); // Error
タプル型
タプルは、固定長で各要素の型が決まっている配列です。
タプルの基本
// タプルの宣言: [型1, 型2, 型3, ...]
let person: [string, number, boolean] = ['Alice', 25, true];
配列との違い
// 配列: すべての要素が同じ型、要素数は可変
let array: number[] = [1, 2, 3, 4, 5];
// タプル: 各位置で型が決まっている、要素数は固定
let tuple: [string, number] = ['Alice', 25];
タプルの型安全性
let userInfo: [string, number, boolean] = ['Alice', 25, true];
// ↑1つ目 ↑2つ目 ↑3つ目
// 各要素の型が保証される
let name: string = userInfo[0]; // OK: string型
let age: number = userInfo[1]; // OK: number型
let isActive: boolean = userInfo[2]; // OK: boolean型
// 型が違うとエラー
// let wrong: number = userInfo[0]; // Error: string型をnumber型に代入できない
// 要素数が違うとエラー
// let wrong: [string, number] = ['Alice', 25, true];
// Error: 要素数が一致しない
分割代入
let data: [string, number, boolean] = ['Alice', 25, true];
// 分割代入で各要素を変数に取り出す
let [name, age, isActive] = data;
console.log(name); // 'Alice'
console.log(age); // 25
console.log(isActive); // true
ラベル付きタプル
TypeScript 4.0以降では、タプルの各要素にラベルを付けられます。
// ラベルなし(従来の方法)
let user1: [string, number, boolean] = ['Alice', 25, true];
// ラベル付き(読みやすい)
let user2: [name: string, age: number, isActive: boolean] = ['Alice', 25, true];
// 関数の戻り値として使用
function getUserInfo(): [name: string, age: number, email: string] {
return ['Alice', 25, 'alice@example.com'];
}
let [userName, userAge, userEmail] = getUserInfo();
タプルの実践的な使用例
// 例1: 座標を表す
type Point2D = [x: number, y: number];
type Point3D = [x: number, y: number, z: number];
let point: Point2D = [10, 20];
let point3d: Point3D = [10, 20, 30];
// 例2: RGB色の表現
type RGB = [red: number, green: number, blue: number];
let red: RGB = [255, 0, 0];
let green: RGB = [0, 255, 0];
let blue: RGB = [0, 0, 255];
// 例3: APIのレスポンス
type ApiResponse = [status: number, data: unknown, error: string | null];
let successResponse: ApiResponse = [200, { name: 'Alice' }, null];
let errorResponse: ApiResponse = [404, null, 'Not Found'];
// 例4: キーと値のペア(Map.entries()の戻り値など)
type Entry<K, V> = [key: K, value: V];
let userEntry: Entry<string, number> = ['age', 25];
// 例5: Reactのフック(useState)の戻り値
// const [state, setState] = useState(initialValue);
// 戻り値は [T, (value: T) => void] というタプル
// 例6: 複数の値を返す関数
function getMinMax(numbers: number[]): [min: number, max: number] {
return [Math.min(...numbers), Math.max(...numbers)];
}
const [min, max] = getMinMax([3, 1, 4, 1, 5, 9, 2, 6]);
console.log(`Min: ${min}, Max: ${max}`); // Min: 1, Max: 9
タプル vs オブジェクト
タプルは順序が重要な少数の値をまとめる場合に適しています。 プロパティ名で意味を明確にしたい場合はオブジェクトを使いましょう。
// タプル: 順序で意味が決まる(座標、RGB、min/maxなど)
const point: [number, number] = [10, 20];
// オブジェクト: プロパティ名で意味が明確
const user = { name: 'Alice', age: 25 };
試してみよう: ユーザー情報を型付けしよう ★
以下の要件を満たすユーザー情報の変数を作成してください。
要件:
userName: 自分の名前(string型)userAge: 自分の年齢(number型)isStudent: 学生かどうか(boolean型)hobbies: 趣味の配列(string[]型)profile: タプル型 [名前, 年齢, 所在地]
作成したデータをコンソールに出力して確認しましょう。
ヒント
- 基本型の変数は型推論を活用してもOK
- 配列は
['趣味1', '趣味2', '趣味3']の形式で作成 - タプルは
[string, number, string]の型注釈を付ける - テンプレートリテラルを使って出力すると見やすい
回答と解説
// 基本的な型(型推論を活用)
let userName = '田中太郎';
let userAge = 25;
let isStudent = true;
// 配列(趣味のリスト)
let hobbies: string[] = ['読書', 'プログラミング', '映画鑑賞'];
// タプル(固定された構造のデータ)
let profile: [string, number, string] = ['田中太郎', 25, '東京都'];
// コンソールに出力
console.log(`名前: ${userName}`);
console.log(`年齢: ${userAge}歳`);
console.log(`学生: ${isStudent ? 'はい' : 'いいえ'}`);
console.log(`趣味: ${hobbies.join(', ')}`);
console.log(`プロフィール: ${profile[0]}(${profile[1]}歳)- ${profile[2]}`);
// 出力例:
// 名前: 田中太郎
// 年齢: 25歳
// 学生: はい
// 趣味: 読書, プログラミング, 映画鑑賞
// プロフィール: 田中太郎(25歳)- 東京都
解説:
userName、userAge、isStudentは初期値から型が推論されるので、型注釈は省略していますhobbiesはstring[]と明示的に型注釈を書いていますが、型推論に任せても問題ありませんprofileはタプル型なので、[string, number, string]と型注釈を書くことで、各位置の型を固定しています- テンプレートリテラルを使うと、変数を埋め込んだ文字列を簡潔に書けます
まとめ
この章で学んだこと:
- number型: 整数・浮動小数点数を表す。数値セパレータで読みやすく書ける
- string型: 文字列を表す。テンプレートリテラルで変数を埋め込める
- boolean型: true/falseの真偽値を表す
- 配列型: 同じ型の複数の値を格納。
型[]またはArray<型>で宣言 - タプル型: 固定長で各要素の型が決まっている配列
- 型推論: 初期値から型を自動推論。明示的な型注釈は初期値がない場合に必要
次の章では、オブジェクト型と型エイリアス(type)について学びます。
初学者がつまずきやすいポイント
よくある間違い
❌ stringとStringを混同する
// ❌ 間違い: オブジェクトラッパー型を使っている
let name: String = 'Alice';
// ✅ 正しい: プリミティブ型を使う
let name: string = 'Alice';
原因: JavaScriptにはString(オブジェクト)とstring(プリミティブ)があり、TypeScriptでは小文字のプリミティブ型を使うのが基本です。
解決策: 型注釈には常に小文字のstring, number, booleanを使用してください。
❌ 配列のpushメソッドの戻り値を誤解する
let fruits: string[] = ['apple'];
// ❌ 間違い: pushは配列を返すと思っている
let newArray = fruits.push('banana');
console.log(newArray); // 2(配列ではなく、新しい長さが返る)
// ✅ 正しい: pushは長さを返す。配列自体が変更される
fruits.push('banana');
console.log(fruits); // ['apple', 'banana']
原因: push()は追加後の配列の長さを返します。
解決策: 新しい配列が必要な場合はスプレッド構文を使用してください。
let newArray = [...fruits, 'orange'];
❌ タプルと配列を混同する
// ❌ 間違い: タプルに型注釈なしで宣言すると配列になる
let point = [10, 20]; // number[] と推論される
point.push(30); // OK(配列なので要素追加可能)
// ✅ 正しい: タプルは明示的に型注釈を書く
let point: [number, number] = [10, 20];
// point.push(30); // 型エラーにはならないが、意図しない動作
原因: 型推論では[10, 20]はnumber[]として扱われます。
解決策: タプルを使いたい場合は必ず型注釈を明示してください。
❌ 読み取り専用配列を変更しようとする
let numbers: readonly number[] = [1, 2, 3];
// ❌ 間違い: readonlyな配列を変更しようとする
numbers.push(4); // Error: Property 'push' does not exist
numbers[0] = 10; // Error: Index signature only permits reading
// ✅ 正しい: 新しい配列を作成する
let newNumbers = [...numbers, 4];
原因: readonly修飾子は配列の変更を禁止します。
解決策: 変更が必要な場合は新しい配列を作成するか、readonlyを外してください。
❌ NaNの比較に===を使う
let result = parseInt('abc'); // NaN
// ❌ 間違い: NaNは自身と等しくない
if (result === NaN) { // 常にfalse
console.log('Invalid number');
}
// ✅ 正しい: Number.isNaN()を使う
if (Number.isNaN(result)) {
console.log('Invalid number');
}
原因: JavaScriptの仕様でNaN === NaNは常にfalseです。
解決策: Number.isNaN()関数を使用してNaNを判定してください。