TypeScriptデコレーターの基本使い方と応用テクニックを徹底解説

TypeScriptにおけるデコレーターは、クラスやメソッド、プロパティ、パラメータに対して追加の機能を付与するための機能です。デコレーターは、オブジェクト指向プログラミングにおいて一般的に使用されており、コードの再利用性や可読性を向上させる効果があります。特に、クラスの振る舞いを柔軟に変更したり、特定のメタデータを追加する際に役立ちます。本記事では、デコレーターの基本的な使い方から実際の応用例までを詳しく解説し、開発に役立つスキルを習得できるようにします。

目次

デコレーターの基本概念

デコレーターは、クラスやそのメンバー(メソッド、プロパティ、パラメータなど)に対して追加の機能を付与するための特別な構文です。TypeScriptでは、デコレーターは関数として実装され、クラスやメンバーに適用されることで、それらの動作を修正、拡張、あるいは補完します。デコレーターは、JavaScriptのメタプログラミングの一環として、コードのアノテーションや動的変更を可能にします。

デコレーターの基本的な仕組みとしては、指定された対象(クラスやメソッドなど)に適用される前後で、その対象のメタデータを操作したり、ロジックを追加したりすることが可能です。

デコレーターを有効化するための設定方法

TypeScriptでデコレーターを使用するには、まず設定を変更してデコレーター機能を有効化する必要があります。TypeScriptのコンパイラはデフォルトでデコレーターを無効化しているため、コンパイル時にエラーを避けるために特定のオプションを設定します。

tsconfig.jsonの設定

デコレーターを有効にするためには、TypeScriptのプロジェクト設定ファイルであるtsconfig.jsonに、以下の設定を追加します。

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}
  • experimentalDecorators: true
    デコレーターの使用を許可するためのオプションです。この設定がないとデコレーターは無効になります。
  • emitDecoratorMetadata: true
    クラスやメソッドにメタデータを付与するための設定です。デコレーターが動作する際、対象のクラスやメソッドに関する情報を提供する役割を果たします。

この設定を行うことで、TypeScriptプロジェクト内でデコレーターを利用できるようになります。

クラスデコレーターの使い方

クラスデコレーターは、クラスそのものに対して適用され、クラスの機能を拡張したり、特定のメタデータを追加したりするために使用されます。クラスデコレーターは、コンストラクタに対して直接適用されるため、クラスが生成される際の振る舞いを変更したり、インスタンスを管理するためのロジックを追加することができます。

クラスデコレーターの基本構造

クラスデコレーターは、クラスを引数として受け取る関数として実装されます。次のコード例では、シンプルなクラスデコレーターの使い方を示します。

function LogClass(target: Function) {
  console.log(`クラス ${target.name} が定義されました`);
}

@LogClass
class User {
  constructor(public name: string) {}
}

この例では、LogClassというクラスデコレーターがUserクラスに適用されています。このデコレーターは、Userクラスが定義された際にクラス名をログに出力します。

デコレーターでクラスを拡張する

デコレーターは、クラスの振る舞いを変更することも可能です。例えば、以下の例では、クラスのコンストラクタに新しいプロパティを追加するデコレーターを示します。

function AddTimestamp(constructor: Function) {
  constructor.prototype.timestamp = new Date();
}

@AddTimestamp
class Article {
  title: string;
  constructor(title: string) {
    this.title = title;
  }
}

const article = new Article("TypeScript Basics");
console.log(article.timestamp); // 現在の日付が表示される

この例では、AddTimestampというデコレーターを使って、Articleクラスにtimestampというプロパティを追加しています。新しいインスタンスが作成されると、自動的に現在の日付がtimestampに設定されます。

クラスデコレーターは、クラス全体の動作や構造を一括して変更できる強力なツールです。

メソッドデコレーターの使い方

メソッドデコレーターは、クラスのメソッドに適用され、そのメソッドの振る舞いを変更したり、特定のロジックを追加するために使用されます。メソッドの呼び出し時に何らかの処理を挿入したい場合や、メソッドの実行結果を監視・記録したい場合に便利です。

メソッドデコレーターの基本構造

メソッドデコレーターは、以下の3つの引数を受け取る関数として実装されます。

  1. target: メソッドが所属するクラスのプロトタイプ(インスタンスメソッドの場合)またはクラスコンストラクタ(静的メソッドの場合)。
  2. propertyKey: デコレーターが適用されたメソッドの名前。
  3. descriptor: メソッドのプロパティディスクリプタ。

次のコード例では、メソッドデコレーターの基本的な使い方を示します。

function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`メソッド ${propertyKey} が呼び出されました`);
    console.log(`引数: ${JSON.stringify(args)}`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class Calculator {
  @LogMethod
  add(a: number, b: number): number {
    return a + b;
  }
}

const calculator = new Calculator();
console.log(calculator.add(2, 3)); // ログが出力され、計算結果が表示される

この例では、LogMethodというメソッドデコレーターを使い、Calculatorクラスのaddメソッドが呼び出されるたびにログを出力します。デコレーターは、元のメソッドの動作を保持しつつ、引数やメソッドの呼び出し情報をログに記録しています。

メソッドの振る舞いを変更する

メソッドデコレーターは、メソッドの振る舞いを変更することもできます。次の例では、メソッドの実行結果をキャッシュするデコレーターを作成します。

function CacheResult(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  const cache = new Map();

  descriptor.value = function (...args: any[]) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      console.log('キャッシュから結果を取得');
      return cache.get(key);
    } else {
      const result = originalMethod.apply(this, args);
      cache.set(key, result);
      return result;
    }
  };

  return descriptor;
}

class MathOperations {
  @CacheResult
  multiply(a: number, b: number): number {
    console.log('計算中...');
    return a * b;
  }
}

const operations = new MathOperations();
console.log(operations.multiply(2, 3)); // 計算される
console.log(operations.multiply(2, 3)); // キャッシュから結果が返される

この例では、CacheResultというデコレーターを使用して、multiplyメソッドの計算結果をキャッシュします。最初の呼び出しでは計算が実行されますが、同じ引数で再度呼び出した場合は、キャッシュされた結果が返されるようになります。

メソッドデコレーターは、関数の前後に特定の処理を挿入したり、メソッドの振る舞いを変更したい場合に非常に有用です。

アクセサデコレーターの使い方

アクセサデコレーターは、クラスのプロパティのゲッター(get)やセッター(set)に対して適用され、そのアクセス方法を制御したり、追加のロジックを挿入するために使用されます。プロパティへのアクセスを監視したり、値を設定する際にバリデーションを行う場合などに利用されます。

アクセサデコレーターの基本構造

アクセサデコレーターは、メソッドデコレーターと同様に、次の3つの引数を受け取ります。

  1. target: アクセサが所属するクラスのプロトタイプ。
  2. propertyKey: アクセサが適用されたプロパティの名前。
  3. descriptor: アクセサのプロパティディスクリプタ。

次のコード例では、プロパティのgetsetをデコレーターでカスタマイズする基本的な例を示します。

function LogAccess(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalGet = descriptor.get;
  const originalSet = descriptor.set;

  descriptor.get = function () {
    console.log(`プロパティ ${propertyKey} の値が取得されました`);
    return originalGet?.apply(this);
  };

  descriptor.set = function (value: any) {
    console.log(`プロパティ ${propertyKey} に値が設定されました: ${value}`);
    originalSet?.apply(this, [value]);
  };

  return descriptor;
}

class Person {
  private _name: string = '';

  @LogAccess
  get name(): string {
    return this._name;
  }

  set name(value: string) {
    this._name = value;
  }
}

const person = new Person();
person.name = "Alice"; // プロパティに値が設定されました: Alice
console.log(person.name); // プロパティの値が取得されました

この例では、LogAccessというアクセサデコレーターを用いて、nameプロパティのゲッターとセッターが呼び出されるたびにログを出力する仕組みを作成しています。nameプロパティに値が設定されたり、取得されたりする際に、その操作がログに記録されます。

アクセサデコレーターでバリデーションを追加する

アクセサデコレーターは、プロパティの値を設定する際にバリデーションを行うためにも使えます。次の例では、ageプロパティに不正な値が設定されないように制限を加えています。

function ValidateAge(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalSet = descriptor.set;

  descriptor.set = function (value: number) {
    if (value < 0 || value > 120) {
      throw new Error("無効な年齢です");
    }
    originalSet?.apply(this, [value]);
  };

  return descriptor;
}

class User {
  private _age: number = 0;

  @ValidateAge
  get age(): number {
    return this._age;
  }

  set age(value: number) {
    this._age = value;
  }
}

const user = new User();
user.age = 25; // 正常に値が設定される
console.log(user.age); // 25が出力される
user.age = -5; // エラー: 無効な年齢です

この例では、ValidateAgeデコレーターを使用して、ageプロパティに無効な値(負の値や120を超える値)が設定されるのを防いでいます。不正な値が入力されると、エラーメッセージが表示されます。

アクセサデコレーターは、プロパティのゲッターやセッターに対して柔軟な制御やバリデーションを追加するために非常に便利で、プロパティの状態管理を厳密に行いたい場合に役立ちます。

プロパティデコレーターの使い方

プロパティデコレーターは、クラスのプロパティ自体に対して適用され、そのプロパティに関するメタデータを追加したり、プロパティのアクセス方法や振る舞いを制御するために使用されます。プロパティデコレーターは、プロパティに直接機能を付与するため、オブジェクトの状態管理やデータ検証を強化する際に非常に有効です。

プロパティデコレーターの基本構造

プロパティデコレーターは、次の2つの引数を受け取る関数として実装されます。

  1. target: プロパティが所属するクラスのプロトタイプ。
  2. propertyKey: デコレーターが適用されたプロパティの名前。

次の例では、プロパティデコレーターを使ってプロパティの操作を追跡する簡単な例を紹介します。

function LogProperty(target: any, propertyKey: string) {
  let value = target[propertyKey];

  const getter = () => {
    console.log(`プロパティ ${propertyKey} の値が取得されました: ${value}`);
    return value;
  };

  const setter = (newValue: any) => {
    console.log(`プロパティ ${propertyKey} に値が設定されました: ${newValue}`);
    value = newValue;
  };

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

class Product {
  @LogProperty
  public price: number;

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

const product = new Product(100);
product.price = 150; // プロパティに値が設定されました: 150
console.log(product.price); // プロパティの値が取得されました: 150

この例では、LogPropertyというプロパティデコレーターを使用して、priceプロパティに対する読み取りや書き込みの際に、その操作をログに記録しています。デコレーターは、プロパティへのアクセスを制御しつつ、プロパティの変更履歴を追跡するのに役立ちます。

プロパティデコレーターでメタデータを付加する

プロパティデコレーターは、プロパティに対するメタデータを付与するためにも使用されます。次の例では、プロパティに対して”required”というメタデータを追加するデコレーターを実装しています。

const requiredMetadataKey = Symbol("required");

function Required(target: any, propertyKey: string) {
  Reflect.defineMetadata(requiredMetadataKey, true, target, propertyKey);
}

function validate(obj: any) {
  for (const key of Object.keys(obj)) {
    const isRequired = Reflect.getMetadata(requiredMetadataKey, obj, key);
    if (isRequired && obj[key] === undefined) {
      throw new Error(`プロパティ ${key} は必須です`);
    }
  }
}

class UserProfile {
  @Required
  public name?: string;

  @Required
  public email?: string;
}

const profile = new UserProfile();
profile.name = "John Doe";
validate(profile); // エラー: プロパティ email は必須です

この例では、@Requiredというデコレーターを使って、nameemailプロパティに必須のメタデータを追加しています。そして、validate関数を利用して、オブジェクトの必須プロパティが設定されているかどうかを検証しています。もし必須のプロパティが未設定であれば、エラーが発生します。

プロパティデコレーターを利用することで、クラスのプロパティに対してメタデータを追加したり、特定のビジネスロジックを組み込むことができ、柔軟なデータ管理が可能となります。

パラメータデコレーターの使い方

パラメータデコレーターは、関数やメソッドの引数に対して適用され、そのパラメータに対するメタデータを追加したり、引数の動作や検証を制御するために使用されます。パラメータデコレーターは、メソッドデコレーターやプロパティデコレーターと組み合わせて、関数の引数に対する制約やロジックを追加するのに役立ちます。

パラメータデコレーターの基本構造

パラメータデコレーターは、次の3つの引数を受け取る関数として実装されます。

  1. target: メソッドが所属するクラスのプロトタイプ。
  2. propertyKey: デコレーターが適用されたメソッドの名前。
  3. parameterIndex: デコレーターが適用された引数の位置(インデックス)。

次の例では、引数に対してパラメータデコレーターを使用し、引数の操作を追跡する仕組みを示します。

function LogParameter(target: any, propertyKey: string, parameterIndex: number) {
  const originalMethod = target[propertyKey];

  target[propertyKey] = function (...args: any[]) {
    console.log(`メソッド ${propertyKey} の引数 ${parameterIndex} は ${args[parameterIndex]} です`);
    return originalMethod.apply(this, args);
  };
}

class Calculator {
  add(@LogParameter a: number, @LogParameter b: number): number {
    return a + b;
  }
}

const calculator = new Calculator();
calculator.add(5, 10); // 引数 0 は 5 です, 引数 1 は 10 です

この例では、LogParameterデコレーターがメソッドの引数に適用されています。addメソッドが呼び出されると、各引数の値がログに出力されます。これにより、特定のパラメータの値を追跡することができます。

パラメータデコレーターでバリデーションを追加する

パラメータデコレーターを使って、関数の引数に対するバリデーションを行うことも可能です。次の例では、引数に対して”必須”という制約を課すデコレーターを実装します。

const requiredParams: number[] = [];

function Required(target: any, propertyKey: string, parameterIndex: number) {
  requiredParams.push(parameterIndex);
}

function validate(target: any, propertyKey: string, args: any[]) {
  for (const index of requiredParams) {
    if (args[index] === undefined) {
      throw new Error(`引数 ${index} は必須です`);
    }
  }
}

class UserService {
  createUser(@Required name: string, @Required email: string) {
    console.log(`ユーザー名: ${name}, メール: ${email}`);
  }
}

const userService = new UserService();
userService.createUser("Alice", "alice@example.com"); // 正常に実行される
userService.createUser("Alice"); // エラー: 引数 1 は必須です

この例では、@Requiredデコレーターを使って、特定の引数が必須であることを宣言しています。validate関数を利用して、実際にメソッドが呼び出される際に引数が正しく提供されているかをチェックし、欠落している場合はエラーを発生させます。

パラメータデコレーターは、メソッドや関数の引数に対して柔軟な制御や検証ロジックを追加するために非常に有効です。これにより、関数の使用を厳密に管理できるようになります。

複数デコレーターを組み合わせた応用例

デコレーターの大きな利点の一つは、複数のデコレーターを同時に適用することで、コードの機能を強力に拡張できる点です。TypeScriptでは、クラス、メソッド、プロパティ、パラメータに対して複数のデコレーターを組み合わせて使用することが可能です。複数のデコレーターを適用するときは、デコレーターは定義された順に適用され、コードの柔軟性や再利用性を向上させることができます。

複数デコレーターの適用方法

次の例では、クラスメソッドに対して複数のデコレーターを適用し、各デコレーターがどのように機能するかを示します。

function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`メソッド ${propertyKey} が呼び出されました`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

function MeasureExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const start = Date.now();
    const result = originalMethod.apply(this, args);
    const end = Date.now();
    console.log(`${propertyKey} の実行時間: ${end - start} ミリ秒`);
    return result;
  };

  return descriptor;
}

class MathOperations {
  @LogMethod
  @MeasureExecutionTime
  multiply(a: number, b: number): number {
    let result = 0;
    for (let i = 0; i < 1000000000; i++) {
      result = a * b; // 処理を重くして時間計測
    }
    return result;
  }
}

const operations = new MathOperations();
console.log(operations.multiply(5, 3)); 

この例では、multiplyメソッドに対してLogMethodMeasureExecutionTimeという2つのメソッドデコレーターが適用されています。各デコレーターは以下のように機能します。

  • LogMethod: メソッドが呼び出されると、そのメソッドの名前がコンソールにログ出力されます。
  • MeasureExecutionTime: メソッドの実行時間を測定し、結果をログに記録します。

実際にメソッドを呼び出すと、最初にLogMethodによってメソッドの呼び出しが記録され、次にMeasureExecutionTimeによって実行時間が計測されます。デコレーターが上から下へ順番に適用されるため、最初に適用されたデコレーターが最後に実行されます。

デコレーターの組み合わせによる実践的な応用例

実践的な開発シーンでは、複数のデコレーターを組み合わせることで、コードの保守性を向上させたり、共通の処理を再利用できるようになります。次の例では、認証チェックとロギングを組み合わせた例を示します。

function AuthCheck(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    if (!this.isAuthenticated) {
      throw new Error("認証されていません");
    }
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

function LogActivity(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`ユーザーが ${propertyKey} メソッドを実行しました`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class UserService {
  public isAuthenticated = true;

  @AuthCheck
  @LogActivity
  getUserData() {
    return { id: 1, name: "John Doe" };
  }
}

const userService = new UserService();
console.log(userService.getUserData()); 

この例では、getUserDataメソッドに対して、以下の2つのデコレーターが適用されています。

  • AuthCheck: メソッドが実行される前にユーザーが認証されているかどうかを確認します。認証されていない場合はエラーを投げます。
  • LogActivity: メソッドが実行された際に、ユーザーのアクションをログに記録します。

デコレーターを組み合わせることで、認証チェックやロギングといった共通の処理をメソッドごとに簡単に再利用でき、効率的なコード管理が可能になります。

このように、複数のデコレーターを使うことで、複雑な処理を簡潔かつ再利用可能にでき、プロジェクトの規模が大きくなるほどその効果は絶大です。

デコレーターの活用によるコードのメリット

デコレーターを活用することで、コードのメンテナンス性や再利用性、可読性が大幅に向上します。デコレーターは関数やクラスの動作を柔軟に拡張するため、特定の機能を各メソッドに埋め込む必要がなくなり、コードの重複を避けることができます。以下に、デコレーターを使用することによる主なメリットを説明します。

1. コードの再利用性

デコレーターを使うことで、特定のロジックや機能を共通化し、異なる場所で簡単に再利用することができます。たとえば、ログ出力、認証チェック、キャッシュ処理といった汎用的な処理をデコレーターとして定義しておくことで、クラスやメソッドごとに同じ処理を繰り返し実装する手間を省けます。

function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`メソッド ${propertyKey} が呼び出されました`);
    return originalMethod.apply(this, args);
  };
}

このようなデコレーターを作成しておけば、任意のメソッドに適用するだけでログ機能を簡単に付加できます。

2. コードの分離と可読性の向上

デコレーターは、ロジックをクラスやメソッドから分離して記述することで、コードの構造をシンプルに保ちます。これにより、各メソッドやクラスが持つ本来の責務に集中でき、コード全体の可読性が向上します。

class UserService {
  @Log
  getUser() {
    return { name: "John Doe" };
  }
}

この例では、getUserメソッドにログ機能が追加されていますが、メソッド自体のロジックはそのままで、ログ出力の処理がコードから分離されています。

3. 一貫した機能追加

デコレーターを使うと、クラスやメソッドに一貫したルールや制約を適用できます。たとえば、全メソッドに対して認証チェックや入力データのバリデーションを必須とする場合、デコレーターを使えばコード全体で一貫した処理が実現できます。

function AuthCheck(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    if (!this.isAuthenticated) {
      throw new Error("認証されていません");
    }
    return originalMethod.apply(this, args);
  };
}

認証チェックが必要なすべてのメソッドにこのデコレーターを適用すれば、個別に認証処理を書く必要がなくなります。

4. メンテナンスの効率化

デコレーターによって共通の処理を外部に切り出すことで、バグの修正や機能の変更が発生した際に、デコレーターのコードを修正するだけで全体に反映できます。これにより、メンテナンスが容易になり、変更による影響範囲の管理が効率化されます。

たとえば、ログ出力の形式を変更したい場合、Logデコレーターを変更するだけで、すべてのメソッドに対して変更が反映されます。

デコレーターは、特に大規模なプロジェクトにおいて、共通処理をシンプルに管理し、保守性を向上させるための強力なツールです。

デコレーターを使ったエラーハンドリングの実装例

デコレーターは、コードに対して一貫したエラーハンドリングを実装する際にも非常に役立ちます。エラーハンドリングの処理をメソッドごとに書く代わりに、デコレーターを使って共通のエラーハンドリングロジックを組み込むことで、コードの重複を避け、保守性を向上させることができます。

エラーハンドリングデコレーターの実装

次の例では、例外が発生した際にエラーメッセージを表示し、例外処理を行うデコレーターを作成します。

function ErrorHandler(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = async function (...args: any[]) {
    try {
      return await originalMethod.apply(this, args);
    } catch (error) {
      console.error(`エラー: ${error.message}`);
    }
  };

  return descriptor;
}

このErrorHandlerデコレーターは、メソッド内で発生したエラーをキャッチし、エラーメッセージをコンソールに出力します。次に、このデコレーターを使ったエラーハンドリングの実例を見てみましょう。

エラーハンドリングの実用例

次のコードでは、ユーザーデータを取得するメソッドにエラーハンドリングデコレーターを適用します。

class UserService {
  @ErrorHandler
  async getUserData(userId: string) {
    if (!userId) {
      throw new Error("ユーザーIDが無効です");
    }
    // 模擬的なデータベース呼び出し(非同期処理)
    return { id: userId, name: "Alice" };
  }
}

const userService = new UserService();
userService.getUserData(""); // エラー: ユーザーIDが無効です

この例では、getUserDataメソッドでユーザーIDが無効な場合にエラーが発生しますが、ErrorHandlerデコレーターを適用しているため、エラーメッセージがコンソールに出力され、プログラムがクラッシュすることを防いでいます。

エラーログの保存と通知

エラーハンドリングデコレーターを拡張して、エラーメッセージをログファイルに保存したり、管理者に通知する機能を追加することも可能です。次の例では、エラーメッセージを外部のロギングサービスに送信する処理を追加しています。

function ErrorLogger(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = async function (...args: any[]) {
    try {
      return await originalMethod.apply(this, args);
    } catch (error) {
      console.error(`エラーが発生しました: ${error.message}`);
      // エラーログを外部サービスに送信(例: Sentry, Loggly)
      logErrorToService(error);
    }
  };

  return descriptor;
}

function logErrorToService(error: Error) {
  // 仮のログ送信処理
  console.log(`エラーがロギングサービスに送信されました: ${error.message}`);
}

class PaymentService {
  @ErrorLogger
  async processPayment(amount: number) {
    if (amount <= 0) {
      throw new Error("支払い金額が無効です");
    }
    // 支払い処理
    return { status: "success", amount };
  }
}

const paymentService = new PaymentService();
paymentService.processPayment(-50); // エラー: 支払い金額が無効です
// エラーログが送信されます

この例では、ErrorLoggerデコレーターがエラー発生時にエラーメッセージをロギングサービスに送信します。エラーが発生したときに単にコンソールに出力するだけでなく、エラーの通知やログ保存といった処理も自動化できるため、エラー管理の一元化が可能です。

デコレーターを使うことで、エラーハンドリングのロジックを簡単に再利用でき、複数のメソッドに対して一貫したエラーハンドリングを実装できます。これにより、コードの保守性が向上し、エラー管理が効率的に行えるようになります。

まとめ

本記事では、TypeScriptにおけるデコレーターの基本的な使い方から、クラス、メソッド、プロパティ、パラメータへの適用方法、さらに複数デコレーターの組み合わせやエラーハンドリングの実装例までを解説しました。デコレーターを活用することで、コードの再利用性や可読性が向上し、メンテナンスが容易になります。特に、共通の処理やエラーハンドリングなど、プロジェクト全体にわたる一貫性を保つためにデコレーターは強力なツールとなります。

コメント

コメントする

目次