[TypeScript]メソッドデコレータ
class Articke{ public name:string; constructor(name:string){ this.name = name; } @logged showName(){ console.log(this.name); } } const art:Articke = new Articke("あいうえお"); art.showName(); setTimeout(art.showName,1000); function logged(originalMethod:any,context:any){ function loggedMethod(this:any,...args:any[]){ console.log(`${context.name}メソッドスタート`); const result = originalMethod.call(this,...args); console.log(`${context.name}メソッド終了`); return result; } return loggedMethod; }
出力
showNameメソッドスタート あいうえお showNameメソッド終了 showNameメソッドスタート undefined showNameメソッド終了
thisをインスタンスに束縛してthis.nameがundefinedになるのを回避する
class Articke{ public name:string; constructor(name:string){ this.name = name; } @bound @logged showName(){ console.log(this.name); } } const art:Articke = new Articke("あいうえお"); art.showName(); setTimeout(art.showName,1000); function logged(originalMethod:any,context:any){ function loggedMethod(this:any,...args:any[]){ console.log(`${context.name}メソッドスタート`); const result = originalMethod.call(this,...args); console.log(`${context.name}メソッド終了`); return result; } return loggedMethod; } //setTimeout(art.showName,1000);のthis.nameがundefinedになるのを回避 function bound(_originalMethod:any,context:any){ context.addInitializer(function(this:any){ this[context.name] = this[context.name].bind(this); }); }
出力
showNameメソッドスタート あいうえお showNameメソッド終了 showNameメソッドスタート あいうえお showNameメソッド終了
型を設定すると…
function logged<This,Args extends any[],Return>( originalMethod:(this:This,...args:Args) => Return, context:ClassMethodDecoratorContext<This,(this:This,...args:Args) => Return> ){ function loggedMethod(this:This,...args:Args):Return{ console.log(`${context.name.toString()} start`); const result = originalMethod.call(this,...args); console.log(`${context.name.toString()} finish`); return result; } return loggedMethod; } function bound<This,Args extends any[],Return>( _originalMethod:(this:This,...args:Args) => Return, context:ClassMethodDecoratorContext<This,(this:This,...args:Args) => Return> ){ context.addInitializer(function(this:any){ this[context.name] = this[context.name].bind(this); }); } class Article{ protected name:string; constructor(name:string){ this.name = name; } @bound @logged showData():void{ console.log(this.name); } } const article = new Article("John Smith"); article.showData(); setTimeout(article.showData,1000);
出力
showData start John Smith showData finish //1秒待つ showData start John Smith showData finish