TypeScript完全ガイド:型システムから高度な機能まで

TypeScriptとは

TypeScriptはJavaScriptのスーパーセットとして設計されたプログラミング言語です。JavaScriptの全機能を継承しつつ、静的型付けシステムを導入することで、大規模アプリケーションの開発をより安全かつ効率的にします。コンパイル時に型チェックを行うため、実行前に多くのエラーを検出できます。

基本的なデータ型

TypeScriptでは、変数宣言にvarletconstが使用できますが、スコープの問題を避けるため、通常はletconstを推奨します。

let counter = 10;
let emptyValue: undefined = undefined;
// constは定数を宣言し、初期化後に値を変更できません
const maxNumber: number = 100;

変数とデータ型

TypeScriptはJavaScriptのデータ型を継承し、さらにいくつかの型を追加しています。主なデータ型を見ていきましょう。

1. boolean

論理値を表し、trueとfalseの2つの値を取ります。

let isActive: boolean = true;

2. number

整数と浮動小数点数を表します。

const price: number = 19.99;

3. string

単一引用符'、二重引用符"、またはバッククォート`で文字列を表現します。バッククォートは複数行文字列や式の埋め込みに使用できます。

let currentYear: string = "2023年";
let greeting: string = `こんにちは、今は${currentYear}です`;

4. 配列 Array

型名[]または配列ジェネリックArray<要素型>で表現します。

let numbers: number[] = [10, 20, 30];
let moreNumbers: Array<number> = [40, 50, 60];

numbers.push(70) // 末尾に追加
numbers.unshift(0) // 先頭に挿入 0 10 20 30 70
numbers.pop() // 末尾を削除 0 10 20 30
numbers.splice(1,2) // 指定位置から指定数削除 0 30
numbers.shift() // 先頭を削除 30
numbers = numbers.concat(moreNumbers) // 配列を結合 
numbers.indexOf(50) // 要素の最初の出現位置を検索
numbers.sort() // ソート
numbers.reverse() // 配列の順序を反転

5. タプル Tuple

要素数と各要素の型が固定された配列を表します。

let userInfo: [string, number];
userInfo = ['Taro', 25]; // 正しい
userInfo = [30, 'Jiro']; // エラー

6. 列挙型 enum

関連する定数の集合を定義します。

enum Status {Pending, Approved, Rejected}
let applicationStatus: Status = Status.Approved; // 1 デフォルトでは0から始まる

enum Status {Pending = 1, Approved = 2, Rejected = 3} // メンバーの値を手動で指定も可能

7. any

任意の型の値を代入できる変数を宣言します。

let flexibleVar: any = 42;
flexibleVar = "文字列にも変更可能";

8. void

型がないことを表し、主に関数が値を返さない場合に使用します。

function showMessage(): void {
    console.log("メッセージを表示");
}

9. nullとundefined

nullはオブジェクト値が欠如していることを、undefinedは値が未定義であることを表します。

let nullValue: null = null;
let undefinedValue: undefined = undefined;

10. neverとobject

neverは決して発生しない値の型を、objectはプリミティブ型でない型を表します。

let errorObject: object = {};

条件分岐とループ

1. 条件分岐

if…else if…else

if(score > 80) { 
    console.log("優秀です") 
} else if(score > 60) { 
    console.log("合格です") 
} else { 
    console.log("不合格です") 
}

switch…case

switch(color) { 
    case "red": { 
        console.log("赤色"); 
        break; 
    } 
    case "blue": { 
        console.log("青色"); 
        break; 
    } 
    default: { 
        console.log("その他の色"); 
        break;              
    } 
}

三項演算子

let result = age >= 20 ? "成人" : "未成年"
console.log(result) // 年齢に応じて結果が変わる

2. ループ処理

for ループ

for(let i = 1; i <= 5; i++) {
   console.log(i);
}

for…in ループとfor…of ループ

// for..in はインデックスを反復処理
let word:any="hello"
for(let index in word) { 
    console.log(index)       //0 1 2 3 4
    console.log(word[index]) //h e l l o
}
// for..of は要素を反復処理
let items= [1, "text", true];
for (let element of items) {
    console.log(element); // 1, "text", true
}

while ループとdo…while ループ

let count=5
while(count > 0) {  
    count--; 
    console.log(count)// 4 3 2 1 0
} 

let value=5
do { 
    console.log(value); // 5 4 3 2 1
    value--; 
} while(value > 0);

関数

TypeScriptでは、関数のパラメータ型と戻り値の型を指定できます。戻り値の型は省略可能で、TypeScriptが自動的に推論します。

通常の関数

function multiply (num1:number, num2: number): number {
    return num1 * num2
}

匿名関数(関数式)

const divide=function(num1:number, num2: number): number{
	return num1 / num2
}

アロー関数

const subtract = (num1:number, num2: number): number => {
    return num1 - num2
}

パラメータの種類

  • オプションパラメータ:パラメータ名後に?を付けて定義
  • デフォルトパラメータ:デフォルト値を持つパラメータ
  • 残余パラメータ:不特定数のパラメータ
function createFullName(firstName: string, lastName?: string): void {
    console.log(`名前: ${firstName} ${lastName || ''}`)
}

function greet(name: string, greeting = "こんにちは"): void {
    console.log(`${greeting}、${name}さん!`)
}

function concatenate(separator: string, ...strings: string[]) {
    return strings.join(separator);
}

クラス

クラスはユーザー定義のデータ型で、プロパティとメソッドを持ちます。TypeScriptではclassキーワードでクラスを定義し、newでインスタンス化します。staticキーワードは静的メンバー(プロパティとメソッド)を定義し、これらはクラス自体に存在し、クラス名.メンバー名で呼び出します。

class Vehicle {
	static description: string = "これはVehicleクラスです"
    brand: string;
	
    constructor(brand: string) {
        this.brand = brand;
    }

	static displayInfo(): void {
        console.log(Vehicle.description);
    }
    
    drive(): void {
        console.log(`${this.brand}の車を運転中です。`);
    }
}

let car = new Vehicle('Toyota');
car.drive(); // Toyotaの車を運転中です。
Vehicle.displayInfo(); // これはVehicleクラスです

継承

TypeScriptは一度に1つのクラスしか継承できません(多重継承はサポートしていません)。クラスの継承にはextendsキーワードを使用します。superキーワードは親クラスへの参照です。

class ElectricCar extends Vehicle {
    drive() {
        super.drive();// 親クラスのメソッドを呼び出し
        console.log('静かで環境に優しい運転です!');
    }
}

let tesla = new ElectricCar('Tesla');
tesla.drive() // Teslaの車を運転中です。静かで環境に優しい運転です!

抽象クラス

抽象クラス自体はインスタンス化できませんが、他の派生クラスの基底クラスとして使用でき、派生クラスは抽象メソッドを実装する必要があります。abstractキーワードで抽象クラスと抽象メソッドを定義します。

abstract class Animal {
    abstract makeSound(): void;
    move(): void {
        console.log('動物が動いています...');
    }
}

カプセル化

TypeScriptではアクセス修飾子とゲッター/セッターの設定により、クラスをカプセル化できます。

  • public:デフォルト、どこからでもアクセス可能
  • protected:クラス自身とそのサブクラスからアクセス可能
  • private:定義されたクラス内のみアクセス可能
class Employee {
    private _salary: number;

    constructor(salary: number) {
        this._salary = salary;
    }
	set salary(newSalary: number) {
        if (newSalary > 0) {
            this._salary = newSalary;
        }
    }
    get salary(): number {
        return this._salary;
    }
}

let employee = new Employee(50000);
employee.salary = 60000
console.log(employee.salary); // 60000

インターフェース

インターフェースはinterfaceキーワードで定義し、implementsキーワードで実装します。1つのクラスは複数のインターフェースを同時に実装できます。

interface Flyable {
	fly(): void;
}

class Bird extends Animal implements Flyable {
	makeSound(){
        console.log("鳴き声");
    }
    
	fly(){
        console.log("空を飛んでいます");
    }
}

let sparrow = new Bird();
sparrow.fly()

モジュール

通常、コードは必要に応じて複数のファイル(モジュール)に分割されます。モジュール内で定義された変数、関数、クラスなどはモジュール外からは見えず、exportでエクスポートする必要があります。対応して、importでインポートできます。

// utils.ts
export function formatDate(date: Date): string {
    return `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`;
}
// app.ts
import { formatDate } from './utils';
console.log(formatDate(new Date()));

ジェネリック

ジェネリックを使用すると、関数、クラス、インターフェースなどを定義する際に、具体的な型ではなくプレースホルダーを使用して型を表現できます。

function createPair<S, T>(first: S, second: T): [S, T] {
    return [first, second];
}

let pair = createPair<string, number>("answer", 42); // 型パラメータはstringとnumber
let anotherPair = createPair(true, false); // コンパイラがSとTをbooleanと推論

タグ: TypeScript 型システム ジェネリック クラス インターフェース

6月7日 23:30 投稿