チュートリアル

TypeScript基礎:条件分岐とループ

TypeScript入門制御構文
広告エリア

条件分岐

if文

const age: number = 20;

if (age >= 20) {
  console.log("成人です");
} else if (age >= 13) {
  console.log("ティーンエイジャーです");
} else {
  console.log("子供です");
}

型による条件分岐

function processValue(value: string | number): void {
  if (typeof value === "string") {
    // この中ではvalueはstring型
    console.log(value.toUpperCase());
  } else {
    // この中ではvalueはnumber型
    console.log(value.toFixed(2));
  }
}

switch文

type Status = "pending" | "approved" | "rejected";

function getStatusMessage(status: Status): string {
  switch (status) {
    case "pending":
      return "審査中です";
    case "approved":
      return "承認されました";
    case "rejected":
      return "却下されました";
    // defaultは不要(網羅性チェック)
  }
}

網羅性チェック

type Color = "red" | "green" | "blue";

function getColorCode(color: Color): string {
  switch (color) {
    case "red":
      return "#FF0000";
    case "green":
      return "#00FF00";
    case "blue":
      return "#0000FF";
    default:
      // 到達不可能なコード
      const _exhaustive: never = color;
      return _exhaustive;
  }
}

// 新しい色を追加するとコンパイルエラーで気づける

三項演算子

const age: number = 20;
const status: string = age >= 20 ? "成人" : "未成年";

// ネストは避ける
const message: string =
  age >= 65 ? "シニア" :
  age >= 20 ? "成人" :
  "未成年";

型ガード

typeof ガード

function double(value: string | number): string | number {
  if (typeof value === "string") {
    return value + value;
  }
  return value * 2;
}

instanceof ガード

class Dog {
  bark(): void {
    console.log("ワン!");
  }
}

class Cat {
  meow(): void {
    console.log("ニャー!");
  }
}

function makeSound(animal: Dog | Cat): void {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    animal.meow();
  }
}

in ガード

interface Bird {
  fly(): void;
}

interface Fish {
  swim(): void;
}

function move(animal: Bird | Fish): void {
  if ("fly" in animal) {
    animal.fly();
  } else {
    animal.swim();
  }
}

カスタム型ガード

interface User {
  type: "user";
  name: string;
}

interface Admin {
  type: "admin";
  name: string;
  permissions: string[];
}

// 型述語(type predicate)
function isAdmin(person: User | Admin): person is Admin {
  return person.type === "admin";
}

function greet(person: User | Admin): void {
  if (isAdmin(person)) {
    console.log(`管理者 ${person.name} さん、権限: ${person.permissions.join(", ")}`);
  } else {
    console.log(`${person.name} さん、こんにちは`);
  }
}

ループ

for文

// 基本のfor文
for (let i: number = 0; i < 5; i++) {
  console.log(i);
}

// for...of(値を取得)
const fruits: string[] = ["apple", "banana", "orange"];
for (const fruit of fruits) {
  console.log(fruit);
}

// for...in(キーを取得)
const user = { name: "太郎", age: 25 };
for (const key in user) {
  console.log(key);  // "name", "age"
}

for…of と型

// 配列
const numbers: number[] = [1, 2, 3];
for (const num of numbers) {
  // num は number 型
  console.log(num * 2);
}

// Map
const map = new Map<string, number>([
  ["one", 1],
  ["two", 2]
]);
for (const [key, value] of map) {
  // key: string, value: number
  console.log(`${key}: ${value}`);
}

// Set
const set = new Set<string>(["a", "b", "c"]);
for (const item of set) {
  console.log(item);
}

while文

let count: number = 0;

while (count < 5) {
  console.log(count);
  count++;
}

// do...while
let input: string;
do {
  input = prompt("'exit'と入力してください") || "";
} while (input !== "exit");

break と continue

// break
for (let i = 0; i < 10; i++) {
  if (i === 5) {
    break;  // ループを抜ける
  }
  console.log(i);
}

// continue
for (let i = 0; i < 10; i++) {
  if (i % 2 === 0) {
    continue;  // 次の反復へ
  }
  console.log(i);  // 奇数のみ
}

// ラベル付きbreak
outer: for (let i = 0; i < 3; i++) {
  for (let j = 0; j < 3; j++) {
    if (i === 1 && j === 1) {
      break outer;  // 外側のループを抜ける
    }
    console.log(i, j);
  }
}

配列メソッドとループ

const numbers: number[] = [1, 2, 3, 4, 5];

// forEach
numbers.forEach((num: number, index: number) => {
  console.log(`${index}: ${num}`);
});

// map
const doubled: number[] = numbers.map((num) => num * 2);

// filter
const evens: number[] = numbers.filter((num) => num % 2 === 0);

// find
const found: number | undefined = numbers.find((num) => num > 3);

// some / every
const hasEven: boolean = numbers.some((num) => num % 2 === 0);
const allPositive: boolean = numbers.every((num) => num > 0);

// reduce
const sum: number = numbers.reduce((acc, num) => acc + num, 0);

非同期ループ

// for...of と async/await
async function processItems(items: string[]): Promise<void> {
  for (const item of items) {
    await processItem(item);
  }
}

// 並列処理
async function processItemsParallel(items: string[]): Promise<void> {
  await Promise.all(items.map((item) => processItem(item)));
}

async function processItem(item: string): Promise<void> {
  // 非同期処理
}

実践例:フォームバリデーション

interface ValidationRule {
  type: "required" | "minLength" | "maxLength" | "pattern";
  value?: number | RegExp;
  message: string;
}

interface ValidationResult {
  valid: boolean;
  errors: string[];
}

function validate(input: string, rules: ValidationRule[]): ValidationResult {
  const errors: string[] = [];

  for (const rule of rules) {
    switch (rule.type) {
      case "required":
        if (!input.trim()) {
          errors.push(rule.message);
        }
        break;
      case "minLength":
        if (typeof rule.value === "number" && input.length < rule.value) {
          errors.push(rule.message);
        }
        break;
      case "maxLength":
        if (typeof rule.value === "number" && input.length > rule.value) {
          errors.push(rule.message);
        }
        break;
      case "pattern":
        if (rule.value instanceof RegExp && !rule.value.test(input)) {
          errors.push(rule.message);
        }
        break;
    }
  }

  return {
    valid: errors.length === 0,
    errors
  };
}

// 使用例
const emailRules: ValidationRule[] = [
  { type: "required", message: "メールアドレスは必須です" },
  { type: "pattern", value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: "メールアドレスの形式が正しくありません" }
];

const result = validate("test@example.com", emailRules);
console.log(result.valid);  // true

まとめ

  • if文で条件分岐、型ガードで型を絞り込み
  • switch文と網羅性チェックで安全なコード
  • for...ofで配列やMapをイテレート
  • 型述語(is)でカスタム型ガードを定義
  • 配列メソッドで関数型スタイルのループ

次回は関数と型について詳しく学びます。

広告エリア