【実践TypeScript】デコレータを使いこなす!効率的なコーディングテクニック解説 - Gizanbeak
TypeScript デコレータの実装方法
デコレータとは?
デコレータの実装方法
デコレータは関数として定義されます。デコレータ関数は、デコレータが適用されるターゲット(クラス、メソッド、プロパティなど)を受け取り、そのターゲットを修正または拡張する処理を行います。
クラスデコレータ
クラスデコレータは、クラスに適用されます。以下は、クラスデコレータの例です。
function Logger(constructor: Function) {
console.log(`クラス ${constructor.name} が作成されました。`);
}
@Logger
class MyClass {
// ...
}
この例では、Logger
デコレータはクラス MyClass
が作成されたときにコンソールにメッセージを出力します。
メソッドデコレータ
function Loggable(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`メソッド ${propertyKey} が呼び出されました。`);
return originalMethod.apply(this, args);
};
}
class MyClass {
@Loggable
greet() {
console.log("こんにちは!");
}
}
この例では、Loggable
デコレータはメソッド greet
が呼び出される前にコンソールにメッセージを出力します。
プロパティデコレータ
プロパティデコレータは、プロパティに適用されます。以下は、プロパティデコレータの例です。
function Required(target: any, propertyKey: string) {
throw new Error(`プロパティ ${propertyKey} は必須です。`);
}
class MyClass {
@Required
name: string;
constructor(name: string) {
this.name = name;
}
}
この例では、Required
デコレータはプロパティ name
が設定されていない場合にエラーを発生させます。
デコレータの注意点
- デコレータは、他のデコレータと組み合わせて使用することができます。
- デコレータは、コードの読みやすさを向上させる一方で、複雑化させる可能性もあります。必要に応じて使用することが重要です。
- デコレータは、TypeScript の機能であり、JavaScript では使用できません。
function Logger(constructor: Function) {
console.log(`クラス ${constructor.name} が作成されました。`);
}
@Logger
class MyClass {
// ...
}
const myClass = new MyClass();
クラス MyClass が作成されました。
function Loggable(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`メソッド ${propertyKey} が呼び出されました。`);
return originalMethod.apply(this, args);
};
}
class MyClass {
@Loggable
greet() {
console.log("こんにちは!");
}
}
const myClass = new MyClass();
myClass.greet();
このコードを実行すると、コンソールに以下のメッセージが出力されます。
メソッド greet が呼び出されました。
こんにちは!
function Required(target: any, propertyKey: string) {
throw new Error(`プロパティ ${propertyKey} は必須です。`);
}
class MyClass {
@Required
name: string;
constructor(name: string) {
this.name = name;
}
}
const myClass = new MyClass("John Doe"); // 正常
// const myClass2 = new MyClass(); // エラー: プロパティ name は必須です。
このコードを実行すると、MyClass
のインスタンスが正常に作成されます。しかし、name
プロパティが設定されていない場合はエラーが発生します。
- デコレータを使用して、パフォーマンスの計測を行う
- デコレータを使用して、クラスのメンバーにアクセス制御を行う
- デコレータを使用して、メソッドの引数や戻り値を検証する
関数
デコレータで実現できる機能の一部は、関数を使用して実現できます。以下は、メソッドデコレータの例です。
function Loggable(method: Function) {
return function(...args: any[]) {
console.log(`メソッド ${method.name} が呼び出されました。`);
return method.apply(this, args);
};
}
class MyClass {
greet() {
console.log("こんにちは!");
}
}
const myClass = new MyClass();
const greet = Loggable(myClass.greet);
greet();
このコードは、デコレータ Loggable
を使用せずに、メソッド greet
にログ出力機能を追加しています。
クラス
class Logger {
constructor(private readonly className: string) {}
log() {
console.log(`クラス ${this.className} が作成されました。`);
}
}
class MyClass {
// ...
}
const logger = new Logger("MyClass");
logger.log();
const myClass = new MyClass();
このコードは、デコレータ Logger
を使用せずに、クラス MyClass
が作成されたときにログ出力機能を追加しています。
メタデータ
function Required(target: any, propertyKey: string) {
Reflect.defineMetadata("required", true, target, propertyKey);
}
class MyClass {
@Required
name: string;
constructor(name: string) {
this.name = name;
}
}
const myClass = new MyClass("John Doe"); // 正常
// const myClass2 = new MyClass(); // エラー: プロパティ name は必須です。
const required = Reflect.getMetadata("required", myClass, "name");
if (required) {
console.log("プロパティ name は必須です。");
}
このコードは、デコレータ Required
を使用せずに、プロパティ name
が必須であることをメタデータとして保存しています。
typescript decorator