Skip to content

Reflect Metadata not supported for TC39 decorators #55788

Open
@paulsmithkc

Description

@paulsmithkc

🔎 Search Terms

decorator, experimentalDecorators, emitDecoratorMetadata, TC39, reflect-metadata, Reflect.metadata(k, v)

🕗 Version & Regression Information

This breaks when setting disabling experimental decorators

"experimentalDecorators": false,
"emitDecoratorMetadata": false,

⏯ Playground Link

https://github.com/paulsmithkc/typescript-decorators

💻 Code

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2021",
    "module": "commonjs",
    "outDir": "dist",
    "declaration": true,
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

src/index.ts

import 'reflect-metadata';

function setting(defaultValue: string): any {
  function getType(target: unknown, property: string | symbol) {
    return Reflect.getMetadata('design:type', target, property);
  }
  function settingExperimental(target: unknown, property: string | symbol): void {
    console.log('settingExperimental', { defaultValue, target, property, type: getType(target, property) });
    target[property] = process.env[String(property)] || defaultValue;
    return;
  }
  function settingTC39(_target: unknown, context: ClassFieldDecoratorContext): () => string {
    return function (): string {
      console.log('settingTC39', { defaultValue, target: this, context, type: getType(this, context.name) });
      return process.env[String(context.name)] || defaultValue;
    };
  }
  return function (target: unknown, context: string | symbol | ClassFieldDecoratorContext) {
    if (typeof context !== 'object') {
      return settingExperimental(target, context);
    } else {
      return settingTC39(target, context);
    }
  };
}

class Config {
  @setting('default_1') SETTING_ONE: string;
}
const configInstance = new Config();

run with:

tsc --project tsconfig.json && node dist/index.js

🙁 Actual behavior

Reflect.getMetadata('design:type', target, property) returns undefined.

🙂 Expected behavior

Reflect.getMetadata('design:type', target, property) returns the type of the class field, when using Standard TC39 decorators.

Additional information about the issue

  1. When transpiling with:

    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    The decorator Reflect.metadata("design:type", type) is automatically applied to each class field.

  2. When transpiling with:

    "experimentalDecorators": false,
    "emitDecoratorMetadata": false,

    The decorator Reflect.metadata("design:type", type) is not applied.

  3. When transpiling with:

    "experimentalDecorators": false,
    "emitDecoratorMetadata": true,

    Typescript produces the following error

    Option 'emitDecoratorMetadata' cannot be specified without specifying option 'experimentalDecorators'.
    

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions