配列の型
基本的な配列
// 型[]記法
const numbers: number[] = [1, 2, 3];
const strings: string[] = ["a", "b", "c"];
// Array<型>記法
const booleans: Array<boolean> = [true, false];
// 型推論
const inferred = [1, 2, 3]; // number[]
// 混合配列(ユニオン型)
const mixed: (string | number)[] = [1, "two", 3];
多次元配列
// 2次元配列
const matrix: number[][] = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
// 3次元配列
const cube: number[][][] = [
[[1, 2], [3, 4]],
[[5, 6], [7, 8]]
];
読み取り専用配列
// readonly修飾子
const numbers: readonly number[] = [1, 2, 3];
// numbers.push(4); // エラー
// ReadonlyArray型
const strings: ReadonlyArray<string> = ["a", "b", "c"];
// strings[0] = "x"; // エラー
// as const で完全な読み取り専用
const tuple = [1, 2, 3] as const;
// tuple は readonly [1, 2, 3] 型
タプル
固定長・固定型の配列です。
// 基本的なタプル
const user: [string, number] = ["太郎", 25];
const [name, age] = user; // 分割代入
// ラベル付きタプル(可読性向上)
type User = [name: string, age: number];
const user2: User = ["花子", 30];
// オプション要素
type Point = [number, number, number?];
const point2D: Point = [10, 20];
const point3D: Point = [10, 20, 30];
// 残余要素
type StringNumberBooleans = [string, number, ...boolean[]];
const t: StringNumberBooleans = ["hello", 1, true, false, true];
読み取り専用タプル
type ReadonlyPoint = readonly [number, number];
const point: ReadonlyPoint = [10, 20];
// point[0] = 5; // エラー
// as const でリテラル型
const colors = ["red", "green", "blue"] as const;
// colors は readonly ["red", "green", "blue"] 型
Map
// 基本的なMap
const userMap = new Map<number, string>();
userMap.set(1, "太郎");
userMap.set(2, "花子");
console.log(userMap.get(1)); // "太郎"
console.log(userMap.has(2)); // true
console.log(userMap.size); // 2
// 初期値付き
const map = new Map<string, number>([
["one", 1],
["two", 2],
["three", 3]
]);
// イテレーション
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
// メソッド
map.delete("one");
map.clear();
オブジェクトをキーに
interface User {
id: number;
name: string;
}
const userScores = new Map<User, number>();
const user1: User = { id: 1, name: "太郎" };
const user2: User = { id: 2, name: "花子" };
userScores.set(user1, 100);
userScores.set(user2, 85);
console.log(userScores.get(user1)); // 100
Set
// 基本的なSet
const numberSet = new Set<number>();
numberSet.add(1);
numberSet.add(2);
numberSet.add(2); // 重複は無視
console.log(numberSet.size); // 2
console.log(numberSet.has(1)); // true
// 初期値付き
const stringSet = new Set<string>(["a", "b", "c"]);
// 配列から重複除去
const array = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(array)]; // [1, 2, 3]
// イテレーション
for (const value of stringSet) {
console.log(value);
}
集合演算
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
// 和集合
const union = new Set([...setA, ...setB]);
// Set { 1, 2, 3, 4, 5, 6 }
// 積集合
const intersection = new Set([...setA].filter(x => setB.has(x)));
// Set { 3, 4 }
// 差集合
const difference = new Set([...setA].filter(x => !setB.has(x)));
// Set { 1, 2 }
WeakMap と WeakSet
キーへの参照が弱い(ガベージコレクション対象になる)コレクションです。
// WeakMap(キーはオブジェクトのみ)
const weakMap = new WeakMap<object, string>();
let obj = { id: 1 };
weakMap.set(obj, "data");
console.log(weakMap.get(obj)); // "data"
// obj = null にするとエントリもGC対象
// WeakSet
const weakSet = new WeakSet<object>();
weakSet.add({ id: 1 });
配列の型ガード
// 配列かどうかのチェック
function processValue(value: string | string[]): void {
if (Array.isArray(value)) {
// value は string[] 型
value.forEach(item => console.log(item));
} else {
// value は string 型
console.log(value);
}
}
// null/undefinedを除去
const arr: (string | null)[] = ["a", null, "b", null, "c"];
const filtered: string[] = arr.filter((item): item is string => item !== null);
ユーティリティ型と配列
// 配列の要素型を取得
type ArrayElement<T> = T extends (infer U)[] ? U : never;
const numbers = [1, 2, 3];
type Num = ArrayElement<typeof numbers>; // number
// タプルからユニオン型
const tuple = ["a", 1, true] as const;
type TupleUnion = (typeof tuple)[number]; // "a" | 1 | true
実践例:型安全なフィルタリング
interface User {
id: number;
name: string;
role: "admin" | "user" | "guest";
active: boolean;
}
const users: User[] = [
{ id: 1, name: "太郎", role: "admin", active: true },
{ id: 2, name: "花子", role: "user", active: false },
{ id: 3, name: "次郎", role: "user", active: true },
{ id: 4, name: "三郎", role: "guest", active: true }
];
// フィルタ条件の型
type FilterCondition<T> = {
[K in keyof T]?: T[K] | T[K][];
};
// 型安全なフィルタ関数
function filterBy<T>(items: T[], condition: FilterCondition<T>): T[] {
return items.filter(item => {
for (const [key, value] of Object.entries(condition)) {
const itemValue = item[key as keyof T];
if (Array.isArray(value)) {
if (!value.includes(itemValue as never)) return false;
} else if (itemValue !== value) {
return false;
}
}
return true;
});
}
// 使用例
const activeAdmins = filterBy(users, { role: "admin", active: true });
const activeUsers = filterBy(users, { role: ["admin", "user"], active: true });
実践例:グループ化
function groupBy<T, K extends keyof T>(
items: T[],
key: K
): Map<T[K], T[]> {
const map = new Map<T[K], T[]>();
for (const item of items) {
const value = item[key];
const group = map.get(value) || [];
group.push(item);
map.set(value, group);
}
return map;
}
// 使用例
interface Product {
id: number;
name: string;
category: string;
}
const products: Product[] = [
{ id: 1, name: "りんご", category: "果物" },
{ id: 2, name: "にんじん", category: "野菜" },
{ id: 3, name: "バナナ", category: "果物" }
];
const grouped = groupBy(products, "category");
// Map { "果物" => [...], "野菜" => [...] }
まとめ
T[]またはArray<T>で配列の型を指定readonlyで読み取り専用配列- タプルで固定長・固定型の配列
Map<K, V>でキーと値の型を指定Set<T>で重複のないコレクションArray.isArrayと型述語で型ガードas constでリテラル型のタプル
次回はクラスについて学びます。