Reflect.getMetadata("design:type", ...)で得られる型まとめ

# 検証環境
## バージョン
| library | version |
|:-----------|:------------|
| Node.js       | v16.13.1        |
| Typescript     | v4.5.4      |
| [reflect-metadata](https://www.npmjs.com/package/reflect-metadata)       | v0.1.13        |

## tsconfig.json
必要な設定を有効化しておく。
```json
{
  "experimentalDecorators": true,
  "emitDecoratorMetadata": true
}
```

# 検証方法
jestテストファイルに型チェックできるProperty Decoratorを用意した。
別にDecoratorにする必要はないがプロパティ定義と得られる型をまとめて記述できて都合がよかった。

```typescript
function CheckType(expectedType: any): PropertyDecorator {
  return function (target: Object, propertyKey: string | symbol) {
    const reflectedType: Function = Reflect.getMetadata(
      'design:type',
      target,
      propertyKey
    );

    expect(reflectedType).toBe(expectedType);
  };
}

class Test {
  @CheckType(String) s: string;
}
```

# 結果

| プロパティ定義 | expectedType | 備考 | 
|:-------------|:-------------|:----|
| prop: string | String |
| prop: number | Number |
| prop: Boolean | Boolean |
| prop: true | Boolean |
| prop: Date | Date |
| prop: Symbol | Object |
| prop: Map<number, string> | Map | ジェネリック型の内容まではわからない |
| prop: Set<string> | Set |
| prop: SomeClass | SomeClass |
| prop: SomeInterface | Object | `interface SomeInterface {}` |
| prop: ObjectType | Object | `type ObjectType = {};` |
| prop: StringType | String | `type StringType = '';` |
| prop: Function | Function |
| prop: () => string | Function |
| prop: string[] | Array |
| prop: [string, number] | Array |
| prop: {} | Object |
| prop: Object | Object |
| prop: NumberEnum | Number | `enum NumberEnum { A = 0, B }` |
| prop: StringEnum | String | `enum StringEnum { A = 'a', B = 'b' }` |
| prop: MixEnum | Object | `enum MixEnum { A = 'a', B = 1 }` : union型と同様？ |
| prop | Object | 型定義なし |
| prop = '' | Object | 初期化していても型定義が無ければObjectになる |
| prop: null | undefined |
| prop: undefined | undefined |
| prop: any | Object |
| prop: unknown | Object |
| prop: void | undefined |
| prop: never | undefined |
| prop: string \| number | Object |
| prop: 'a' \| 'b' | String | union型 |
| prop: string \| null | String |
| prop: string \| undefined | String |
| prop: string \| any | Object |
| prop: string \| unknown | Object |
| prop: string \| void | Object |
| prop: string \| string[] | Object |
| prop: string & number | Object |
| prop: 'a' & 'b' | String | intersection型。調べた範囲ではunionと同じ結果 |
| prop: string & null | String |
| prop: string & undefined | String |
| prop: string & any | Object |
| prop: string & unknown | Object |
| prop: string & void | Object |
| prop: string & string[] | Object |
| prop: T | Object | `class Test<T>` |
| prop: T2 | String | `class Test<T extends string>` |

# 検証コード全体

```typescript
import 'reflect-metadata';

function CheckType(expectedType: any): PropertyDecorator {
  return function (target: Object, propertyKey: string | symbol) {
    const reflectedType: Function = Reflect.getMetadata(
      'design:type',
      target,
      propertyKey
    );

    expect(reflectedType).toBe(expectedType);
  };
}

describe('Reflect.getMetadata("design:type")', () => {
  test('', () => {
    class SomeClass {}
    interface MyInterface {}
    type ObjectType = {};
    type StringType = '';
    type UnionType1 = string | number;
    type UnionType2 = 'a' | 'b';
    type IntersectionType = string & number;

    enum NumberEnum {
      A = 0,
      B,
    }

    enum StringEnum {
      A = 'a',
      B = 'b',
    }

    enum MixEnum {
      A = 'a',
      B = 1,
    }

    class Test<T, T2 extends string> {
      @CheckType(String) prop0: string;
      @CheckType(String) prop1: string = '';
      @CheckType(Number) prop2: number;
      @CheckType(Boolean) prop3: Boolean;
      @CheckType(Boolean) prop4: true;
      @CheckType(Date) prop5: Date;
      @CheckType(Object) prop6: Symbol;
      @CheckType(Map) prop7: Map<number, string>;
      @CheckType(Set) prop8: Set<string>;
      @CheckType(SomeClass) prop9: SomeClass;
      @CheckType(Object) prop10: MyInterface;
      @CheckType(Object) prop11: ObjectType;
      @CheckType(String) prop12: StringType;
      @CheckType(Function) prop13: Function;
      @CheckType(Function) prop14: () => string;
      @CheckType(Array) prop15: string[];
      @CheckType(Object) prop16: {};
      @CheckType(Object) prop17: Object;
      @CheckType(Object) prop18: unknown;
      @CheckType(Object) prop19: any;
      @CheckType(Number) prop20: NumberEnum;
      @CheckType(String) prop21: StringEnum;
      @CheckType(Object) prop22: MixEnum;
      @CheckType(Object) prop23: string | number;
      @CheckType(String) prop24: 'a' | 'b';
      @CheckType(String) prop25: string | undefined;
      @CheckType(Object) prop26: string | void;
      @CheckType(String) prop27: string | null;
      @CheckType(Object) prop28: string | any;
      @CheckType(Object) prop29: string | unknown;
      @CheckType(Object) prop30: string | string[];
      @CheckType(Object) prop31: string & number;
      @CheckType(String) prop32: 'a' & 'b';
      @CheckType(String) prop33: string & undefined;
      @CheckType(Object) prop34: string & void;
      @CheckType(String) prop35: string & null;
      @CheckType(Object) prop36: string & any;
      @CheckType(Object) prop37: string & unknown;
      @CheckType(Object) prop38: string & string[];
      @CheckType(Array) prop39: [string, number];
      @CheckType(undefined) prop40: void;
      @CheckType(undefined) prop41: never;
      @CheckType(Object) prop42;
      @CheckType(Object) prop43 = '';
      @CheckType(undefined) prop44: null;
      @CheckType(undefined) prop45: undefined;
      @CheckType(Object) prop46: T;
      @CheckType(String) prop47: T2;
    }
  });
});
```