TypeScriptのデコレーターって何？？

## はじめに
TypeScriptの本を読んでいると、デコレーターという物をみました。今までデコレーターってわかっているようでわかっていなかったので、ちょっと学んでみようかなぁと思って記事にしました。

## Decoratorとは何か？？
クラスやクラスのメンバー（メソッド、プロパティなど）に対して追加の機能を動的に付加するためのものらしいです。。うーん、、、ちょっとよくわからない。実際に具体例を交えながら学んでいこうと思います。

https://www.typescriptlang.org/docs/handbook/decorators.html#introduction

## ソースコード

### クラスデコレーター
クラス全体に対して適用されるデコレーターです。
```ts:classDecorator.ts
// biome-ignore lint/complexity/noBannedTypes: <explanation>
function Logger(target: Function) {
	console.log(`クラスが作成されました: ${target.name}`);
}

@Logger
class MyClass {
	constructor() {
		console.log("MyClassのインスタンスが生成されました");
	}
}

const myClassInstance = new MyClass();

```

```shell:実行結果
~/develop/typescript_decorator$ ts-node classDecorator.ts
クラスが作成されました: MyClass
MyClassのインスタンスが生成されました
```

### メソッドデコレーター
メソッドに対して適用されるデコレーターです。
```typescript:methodDecorator.ts
function Log(
	// biome-ignore lint/suspicious/noExplicitAny: This is needed to allow any type for the target
	target: any,
	propertyKey: string,
	descriptor: PropertyDescriptor,
) {
	console.log("111", target, propertyKey, descriptor);
	const originalMethod = descriptor.value;
	console.log("=======22 ", originalMethod);
	// biome-ignore lint/suspicious/noExplicitAny: This is needed to allow any type for the arguments
	descriptor.value = function (...args: any[]) {
		console.log(`メソッド ${propertyKey} が呼び出されました`);
		return originalMethod.apply(this, args);
	};

	return descriptor;
}

class MyClass {
	@Log
	myMethod() {
		console.log("メソッドの実行中...");
	}
}

const myClassInstance = new MyClass();
myClassInstance.myMethod();
```

```shell:実行結果
~/develop/typescript_decorator$ ts-node methodDecorator.ts
111 {} myMethod {
  value: [Function: myMethod],
  writable: true,
  enumerable: false,
  configurable: true
}
=======22  [Function: myMethod]
メソッド myMethod が呼び出されました
メソッドの実行中...
```

### アクセサリーデコレーター
getterまたはsetterのアクセサリに対して適用されるデコレーターです。

```typescript:
function Enumerable(isEnumerable: boolean) {
	// biome-ignore lint/suspicious/noExplicitAny: This is needed to allow any type for the target
	return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
		descriptor.enumerable = isEnumerable;
	};
}

class MyClass {
	private _value = 0;

	@Enumerable(false)
	get value(): number {
		return this._value;
	}

	set value(val: number) {
		this._value = val;
	}
}

const myClassInstance = new MyClass();
console.log(Object.keys(myClassInstance)); // 'value' は表示されない

```

### プロパティデコレーター
プロパティに対して適用されるデコレーターです。

```typescript:propertyDecorator.ts
// biome-ignore lint/suspicious/noExplicitAny: This is needed to allow any type for the target
function ReadOnly(target: any, propertyKey: string) {
	Object.defineProperty(target, propertyKey, {
		writable: false,
	});
}

class MyClass {
	@ReadOnly
	name = "Initial name";
}

const myClassInstance = new MyClass();
try {
	myClassInstance.name = "Changed name"; // エラー: nameは読み取り専用です
} catch (error) {
	// biome-ignore lint/suspicious/noExplicitAny: This is needed to handle any type of error
	console.error((error as any).message);
}

```

```shell:実行結果
~/develop/typescript_decorator$ ts-node propertyDecorator.ts
/Users/kawamurakouji/develop/typescript_decorator/propertyDecorator.ts:10
        name = "Initial name";
     ^
TypeError: Cannot assign to read only property 'name' of object '#<MyClass>'
    at new MyClass (/Users/kawamurakouji/develop/typescript_decorator/propertyDecorator.ts:10:6)
    at Object.<anonymous> (/Users/kawamurakouji/develop/typescript_decorator/propertyDecorator.ts:13:25)
    at Module._compile (node:internal/modules/cjs/loader:1369:14)
    at Module.m._compile (/Users/kawamurakouji/.config/yarn/global/node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/kawamurakouji/.config/yarn/global/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Function.Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at phase4 (/Users/kawamurakouji/.config/yarn/global/node_modules/ts-node/src/bin.ts:649:14)
```

## パラメーターデコレーター
メソッドのパラメータに対して適用されるデコレーターです。

```typescript:parameterDecorator.ts
// biome-ignore lint/suspicious/noExplicitAny: This is needed to allow any type for the target
function LogParameter(target: any, propertyKey: string, parameterIndex: number) {
    const metadataKey = `log_${propertyKey}_parameters`;
    if (Array.isArray(target[metadataKey])) {
      target[metadataKey].push(parameterIndex);
    } else {
      target[metadataKey] = [parameterIndex];
    }
  }
  
  class MyClass {
    myMethod(@LogParameter message: string) {
      console.log(message);
    }
  }
  
  const myClassInstance = new MyClass();
  myClassInstance.myMethod('Hello, world!');
  // 出力: Hello, world!
  
```