読み込み中...

TypeScriptでクラス変数を使いこなす10の方法

TypeScriptのクラス変数を解説する本文のイメージ TypeScript
この記事は約21分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

この記事を読めば、TypeScriptのクラス変数を活用することができるようになります。

クラス変数はTypeScriptの中心的な要素の一つであり、それを理解することでより効果的なプログラミングが可能となります。

●TypeScriptのクラス変数とは

TypeScriptのクラス変数は、クラス内で使用される変数のことを指します。

JavaScriptのクラス概念を拡張して、静的型付けのメリットを持つTypeScriptでは、これらのクラス変数に対して型を指定することができます。

これにより、コードの品質を向上させたり、バグを予防することが可能になります。

具体的には、TypeScriptのクラス変数は、オブジェクト指向プログラミングの一部として、オブジェクトの状態や特性を保持します。

これにより、各インスタンスが持つデータを一元管理し、それに基づいてメソッドなどの動作を制御することができるのです。

また、TypeScriptのクラス変数は、アクセス修飾子や静的な変数といった、様々な機能や特性を活用して、より高度なプログラムを構築する際の基盤となります。

○クラス変数の基本定義

このコードでは、基本的なクラス変数の定義を表しています。

この例では、Personクラス内にnameというクラス変数を持ち、コンストラクタでその値を初期化しています。

class Person {
    // nameというクラス変数を定義
    name: string;

    // コンストラクタでnameを初期化
    constructor(n: string) {
        this.name = n;
    }
}

// インスタンスを生成し、nameに値を設定
const person1 = new Person("Taro");
console.log(person1.name); // Taroを出力

このコードを実行すると、コンソールには「Taro」という名前が表示されます。

このように、クラス変数を通じて、インスタンス毎に異なるデータを保持し、それに基づく動作を実現することができます。

●クラス変数の使い方

TypeScriptを使用する際に、クラス変数の有効な使い方を知ることは、より堅牢でメンテナブルなコードを書くための鍵となります。

ここでは、クラス変数の使い方をいくつかのサンプルコードと共に詳しく解説します。

○サンプルコード1:基本的なクラス変数の定義

TypeScriptでのクラス変数の基本的な定義について解説します。

クラスの内部で変数を宣言すると、それはクラス変数となります。

class Animal {
    name: string;  // クラス変数の定義

    constructor(name: string) {
        this.name = name;  // クラス変数に値を代入
    }

    display() {
        console.log(`この動物の名前は${this.name}です。`);
    }
}

const cat = new Animal('ネコ');
cat.display(); 

このコードではAnimalクラスを定義しています。

この例では、nameというクラス変数を使用して動物の名前を保持しています。

実行を行うと、「この動物の名前はネコです。」というメッセージが出力されます。

○サンプルコード2:クラス変数の型指定

TypeScriptの特長である型指定を活用して、クラス変数にも型を指定できます。

class Rectangle {
    width: number;  // 数値型でのクラス変数定義
    height: number;

    constructor(width: number, height: number) {
        this.width = width;
        this.height = height;
    }

    area() {
        return this.width * this.height;  // 面積の計算
    }
}

const myRectangle = new Rectangle(5, 10);
console.log(myRectangle.area());

このコードでは、Rectangleクラスにwidthheightという数値型のクラス変数を定義しています。

この例では、矩形の面積を計算して出力します。

この場合、5と10の矩形の面積、すなわち50が出力されます。

○サンプルコード3:静的なクラス変数

静的なクラス変数は、クラス自体に紐づけられ、インスタンス間で共有される変数です。

staticキーワードを使用して定義します。

class Counter {
    static count: number = 0;  // 静的なクラス変数

    constructor() {
        Counter.count++;
    }

    static display() {
        console.log(`合計生成数:${Counter.count}`);
    }
}

new Counter();
new Counter();

Counter.display();

このコードでは、Counterクラスのインスタンスが生成されるたびに、静的なクラス変数countの値が増加します。

この例では、「合計生成数:2」というメッセージが出力されます。

○サンプルコード4:アクセス修飾子を使ったクラス変数

TypeScriptでは、クラス変数の可視性を制御するためのアクセス修飾子が提供されています。

ここでは、privateprotected、およびpublicといった基本的なアクセス修飾子を使ってクラス変数の可視性を制御する方法を紹介します。

class Animal {
    public name: string;       // 公開されたクラス変数
    private age: number;      // 非公開のクラス変数
    protected type: string;   // 継承先のクラスからアクセス可能なクラス変数

    constructor(name: string, age: number, type: string) {
        this.name = name;
        this.age = age;
        this.type = type;
    }

    // パブリックメソッド
    public introduce(): string {
        return `私は${this.name}、${this.age}歳の${this.type}です。`;
    }
}

class Dog extends Animal {
    constructor(name: string, age: number) {
        super(name, age, "犬");
    }

    // 犬の種類を返すメソッド
    getDogType(): string {
        return `私は${this.type}です。`;
    }
}

const shiro = new Dog("シロ", 3);
console.log(shiro.introduce()); // 私はシロ、3歳の犬です。

このコードでは、Animalという名前のクラスに、nameagetypeという三つのクラス変数を持っています。

それぞれの変数には、publicprivateprotectedのアクセス修飾子が設定されています。

この例では、name変数はどのクラスからでもアクセス可能な変数として定義されています。

一方、age変数はAnimalクラス内でのみアクセス可能で、外部からはアクセスできません。

また、type変数はAnimalクラスおよびそのサブクラス(この場合はDogクラス)からアクセス可能です。

上記のコードを実行すると、「私はシロ、3歳の犬です。」と表示されます。

アクセス修飾子は、クラス変数やメソッドの可視性を制限することで、データのカプセル化や情報の隠蔽を実現します。

これにより、クラスの外部から直接アクセスすべきでない変数やメソッドを隠し、不正な操作や予期せぬバグのリスクを低減することができます。

●クラス変数の応用例

TypeScriptのクラス変数は、単なる変数格納の手段を超えて、多岐にわたる使い方や応用例が存在します。

ここでは、それらの中から代表的なものをピックアップし、実際のコードとともに詳しくご紹介します。

○サンプルコード5:計算プロパティを使ったクラス変数

このコードでは、計算プロパティを使用してクラス変数の値を動的に計算する方法を表しています。

この例では、widthとheightという2つのクラス変数をもとに、面積を計算して返すgetterメソッドを定義しています。

class Rectangle {
  constructor(public width: number, public height: number) {}

  // 面積を計算するgetterメソッド
  get area() {
    return this.width * this.height;
  }
}

const rectangle = new Rectangle(10, 5);
console.log(rectangle.area);  // 50と表示される

上記のコードを実行すると、rectangle.areaは50として取得されます。

getterメソッドを使うことで、独自の計算ロジックを組み込んだクラス変数を実装することができます。

○サンプルコード6:クラス変数を使用するメソッド

クラス内でのメソッド定義時、クラス変数を用いることで、さまざまな操作を行うことが可能です。

この例では、Studentクラスにおいて、クラス変数を用いて自己紹介文を出力するメソッドを表しています。

class Student {
  constructor(public name: string, public age: number) {}

  introduce() {
    console.log(`私は${this.name}、${this.age}歳です。`);
  }
}

const taro = new Student("太郎", 20);
taro.introduce();  // 私は太郎、20歳です。と表示される

上記のコードでは、introduceメソッドが呼び出されると、私は太郎、20歳です。という文が表示されます。

○サンプルコード7:継承を使ったクラス変数の管理

継承を利用することで、親クラスのクラス変数やメソッドを子クラスでも利用することができます。

この例では、親クラスのクラス変数を子クラスでオーバーライドし、独自の値を設定しています。

class Animal {
  sound: string = "音";
  makeSound() {
    console.log(this.sound);
  }
}

class Dog extends Animal {
  sound = "ワンワン";
}

const dog = new Dog();
dog.makeSound();  // ワンワンと表示される

DogクラスはAnimalクラスを継承していますが、soundクラス変数をオーバーライドして独自の値を持たせています。

そのため、DogのインスタンスからmakeSoundメソッドを呼び出すと、「ワンワン」と表示されます。

○サンプルコード8:ジェネリクスを利用したクラス変数

TypeScriptは、高度な型システムを持っており、その一部として「ジェネリクス」という機能が提供されています。

ジェネリクスを使用すると、一般的な型を持つクラスや関数を定義することができ、後から具体的な型を指定することができます。

これにより、再利用可能で柔軟なコードを書くことが可能となります。

ジェネリクスをクラス変数に応用することで、その変数の型を柔軟に変更することが可能となります。

ジェネリクスを活用してクラス変数を定義する方法のサンプルコードを紹介します。

// Tはジェネリクスの型パラメータ
class Sample<T> {
    // ジェネリクスを利用したクラス変数の定義
    classVariable: T;

    constructor(initialValue: T) {
        this.classVariable = initialValue;
    }
}

// string型のSampleクラスのインスタンスを作成
const stringInstance = new Sample<string>("こんにちは");
console.log(stringInstance.classVariable); // こんにちは

// number型のSampleクラスのインスタンスを作成
const numberInstance = new Sample<number>(12345);
console.log(numberInstance.classVariable); // 12345

このコードでは、Sampleというクラスが定義されており、このクラスはジェネリクスの型パラメータTを持っています。

クラス変数classVariableの型もTとして指定されているため、このクラスをインスタンス化する際に具体的な型を指定することで、その型のデータを持つクラス変数を持つオブジェクトを生成することができます。

この例では、string型とnumber型の2つの異なる型でSampleクラスをインスタンス化しています。

これにより、同じクラス定義を再利用しながら、異なる型のデータを持つクラス変数を持つオブジェクトを簡単に生成することができます。

ジェネリクスを利用することで、様々なデータ型に対応したクラスや関数を簡単に作成することが可能となり、コードの再利用性や柔軟性が向上します。

特に、大規模なアプリケーションやライブラリを開発する際には、このような機能の利用は非常に有効です。

このサンプルコードを実行すると、まずstringInstance.classVariableの結果として「こんにちは」という文字列が出力されます。

次に、numberInstance.classVariableの結果として、12345という数値が出力されます。

○サンプルコード9:デコレータを使ったクラス変数の拡張

TypeScriptでは、デコレータという機能を使用することで、クラスやクラスの変数、メソッドに対して追加の振る舞いや処理を注入することができます。

デコレータは、特定のタイミングや条件でクラス変数に対して特定の操作を自動的に行うための仕組みとして活用されることが多いです。

このコードでは、ログ出力のデコレータを使ってクラス変数に値が設定された際に、その値の変更をコンソールにログとして出力する例を表しています。

この例では、デコレータを使ってクラス変数の値が変わったときに、その変更内容を自動的にログとして取得しています。

// ログ出力のデコレータ
function Log(target: any, propertyKey: string) {
    let value = target[propertyKey];

    const getter = () => {
        console.log(`取得: ${propertyKey} => ${value}`);
        return value;
    };

    const setter = (next: any) => {
        console.log(`設定: ${propertyKey} => ${next}`);
        value = next;
    };

    Object.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true,
    });
}

class User {
    @Log
    public name: string;

    constructor(name: string) {
        this.name = name;
    }
}

const user = new User("Taro");
user.name = "Jiro";  // ここで、name変数に値が設定されると、ログが出力される

上記のコードでは、Userクラスのname変数に@Logデコレータを適用しています。

これにより、このクラス変数に対する取得や設定の際に、デコレータで定義したgettersetterが呼び出され、それぞれの動作が実行されます。

実際に、user.name = "Jiro";の部分でname変数の値を変更すると、コンソールに「設定: name => Jiro」というログが出力されます。

このように、デコレータを使用することで、クラス変数に対する操作を簡単に拡張することが可能となります。

このデコレータの技術は、ログ出力の他にも様々な用途で活用できます。

たとえば、変数の値のバリデーションや変数の変更をトリガーとした何らかの処理を自動的に実行するといったことが考えられます。

○サンプルコード10:モジュールとクラス変数

TypeScriptにおけるモジュールは、変数や関数、クラスなどのメンバーを含むコードの一部をまとめるための仕組みであり、大規模なアプリケーション開発において非常に重要な要素となっています。

クラス変数もこのモジュール内で定義や利用が可能です。

今回はモジュールとクラス変数の組み合わせについて、実際のサンプルコードを通して詳しく解説します。

このコードでは、TypeScriptのモジュールを利用して、クラスとそのクラス変数を定義するコードを表しています。

この例では、Animalクラスをモジュール内で定義し、その中にspeciesというクラス変数を持たせています。

// AnimalModule.ts
export class Animal {
  static species: string = "哺乳動物";
  constructor(public name: string) {}
}

// main.ts
import { Animal } from './AnimalModule';

console.log(Animal.species); // 哺乳動物

上記のコードは、AnimalModule.tsというファイル内にAnimalクラスを定義しています。

このクラスには、speciesという静的クラス変数が存在しており、”哺乳動物”という文字列が初期値として設定されています。

次に、main.tsというファイルでは、先程のモジュールからAnimalクラスをインポートしています。

このファイル内でAnimal.speciesを出力することで、”哺乳動物”という文字列がコンソールに表示されることが期待されます。

このサンプルを実際に実行すると、”哺乳動物”という文字列が正しく出力されるでしょう。

モジュールを利用することで、クラスやその中の変数、メソッドなどを整理して一元的に管理することができます。

これにより、大規模なプロジェクトでもコードの可読性や保守性を向上させることができるのです。

さらに、モジュールを使用することで、クラス変数などのスコープを制限することも可能です。

例えば、特定のモジュールだけで利用されるクラス変数を定義することができ、他のモジュールからのアクセスを制限することができるのです。

●注意点と対処法

TypeScriptでクラス変数を活用する際、多くの利点がありますが、注意すべき点もいくつか存在します。

ここでは、TypeScriptのクラス変数を使用する上での主な注意点とそれを解決するための対処法について説明します。

○初期化の忘れ

TypeScriptのクラス変数は、必ず初期化する必要があります。

初期化を忘れるとエラーが発生する場合があります。

   class Sample {
       // 初期化がないためエラーが発生
       let name: string;
   }

このコードでは、nameというクラス変数を使って文字列を定義していますが、初期化していないのでエラーが発生します。

この問題を解決するためには、クラス変数を宣言する際に初期値を設定するか、コンストラクタ内で初期化を行う必要があります。

   class Sample {
       let name: string = "初心者";
   }

○アクセス修飾子の不正確な使用

TypeScriptのクラス変数には、アクセス修飾子(public, private, protected)を使用して、その変数のアクセス範囲を制御することができます。

しかし、適切なアクセス修飾子を使用しないと、予期しないエラーやバグが発生する恐れがあります。

   class Sample {
       private age: number = 20;

       public displayAge(): void {
           console.log(`年齢は${this.age}歳です。`);
       }
   }

   const sample = new Sample();
   // 外部からのアクセスが不可能なためエラー
   console.log(sample.age);

この例では、ageというクラス変数にprivateというアクセス修飾子を使用しているため、クラスの外部からのアクセスは不可能です。

このような場合、適切なアクセス修飾子を使用するか、getterやsetterを用意することで解決できます。

○静的なクラス変数とインスタンス変数の混同

TypeScriptでは、staticキーワードを使用して、クラスレベルでの変数を定義することができます。

しかし、静的なクラス変数とインスタンス変数を混同すると、予期しない挙動が生じる可能性があります。

   class Sample {
       static count: number = 0;

       incrementCount(): void {
           // ここでエラーが発生
           this.count++;
       }
   }

このコードでは、countは静的なクラス変数として定義されているため、this.countのような形でのアクセスは不正確です。

静的なクラス変数にアクセスする場合は、クラス名を使ってアクセスする必要があります。

   class Sample {
       static count: number = 0;

       incrementCount(): void {
           Sample.count++;
       }
   }

●カスタマイズ方法

TypeScriptでのクラス変数は、そのままの形で利用するだけでなく、さまざまなカスタマイズ方法が存在します。

こちらでは、より効果的にクラス変数を活用するためのカスタマイズ方法とその実際のサンプルコードについて詳しく解説します。

○クラス変数に初期値を設定する

このコードでは、クラス変数に初期値を設定する方法を表しています。

この例では、nameというクラス変数に"Default Name"という初期値を設定しています。

class User {
    // 'name'というクラス変数に初期値"Default Name"を設定
    name: string = "Default Name";
}

const user1 = new User();
console.log(user1.name);  // Default Name

上記のコードを実行すると、"Default Name"という文字列が出力されます。

これにより、新しいインスタンスを作成した際に、指定しなかった場合のデフォルトの値を簡単に設定することができます。

○クラス変数を外部から読み取り専用にする

このコードでは、クラス変数を外部からの読み取り専用として設定する方法を表しています。

この例では、idというクラス変数を読み取り専用readonly修飾子を使って定義しています。

class Order {
    // 'id'というクラス変数を読み取り専用にする
    readonly id: number;

    constructor(id: number) {
        this.id = id;
    }
}

const order1 = new Order(12345);
console.log(order1.id);  // 12345
// order1.id = 67890;  // Error: 'id'は読み取り専用です

上記のコードを実行すると、12345という数字が出力されます。

しかし、読み取り専用としたidクラス変数に後から値を再代入しようとするとエラーが発生します。

このように、クラス変数を読み取り専用にすることで、意図しない値の変更を防ぐことができます。

○クラス変数を動的に計算する

このコードでは、クラス変数の値を動的に計算する方法を表しています。

この例では、fullNameというクラス変数を、firstNamelastNameから動的に生成しています。

class Person {
    firstName: string;
    lastName: string;

    // 'fullName'を動的に計算するゲッター
    get fullName(): string {
        return this.firstName + " " + this.lastName;
    }

    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

const person1 = new Person("Taro", "Yamada");
console.log(person1.fullName);  // Taro Yamada

上記のコードを実行すると、"Taro Yamada"という文字列が出力されます。

このように、ゲッターを使用してクラス変数の値を動的に計算することで、複数のクラス変数の組み合わせに基づいて新しい値を簡単に生成することができます。

まとめ

TypeScriptを学び、より深く理解する中で、クラス変数の知識とその活用法は極めて重要です。

この記事を通じて、TypeScriptのクラス変数の基本から高度な使い方、そしてカスタマイズ方法までを解説いたしました。

本記事が、TypeScript初心者から上級者までの皆さんにとって、クラス変数の理解と活用の一助となれば幸いです。