What it the signature for non-static property decorator in TypeScript 5?

624 Views Asked by At

Although the TypeScript 5 has been officially realized with new decorators, the decorators documentation is still about decorators of TypeScript 4 (for the 1st April 2023).

enter image description here

The signature of decorator functions has been changed. Experimentally I have 2 parameters with undefined first one and metadata-like second one:

export default function VueReactiveDataField(
  ...blackBoxes: Array<unknown>
): void {

  console.log(blackBoxes);

  // ...

}

@VueComponentOptions
export default class ReactiveStateExperimentalSample {

  @VueReactiveDataField
  protected exampleReactiveField: string = "Experimental sample works fine";

}

The console output is:

enter image description here

What it their types and why first one is undefined?

[ Appendix ] tsconfig.json

Of course is has not "experimentalDecorators": true.

{
  "compilerOptions": {

    "target": "ES2020",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,

    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": false, /* Actual for Vue3; see https://github.com/vuejs/vue-next/issues/4668 */
    "allowJs": true, /* Actual for Vue3; */
    "skipLibCheck": true,

    "baseUrl": "./",
    "paths": {
      "@Source/*": [ "./Source/*" ]
    },
    "declaration": true
  },
  "include": [
    "Project.d.ts",
    "Source/**/*",
    "Tests/**/*"
  ]
}
1

There are 1 best solutions below

0
Alex Chashin On BEST ANSWER

You can read about decorators in ECMAScript decorators proposal. Specifically for class field decorators the first argument is always undefined. For the second argument TS5 provides ClassFieldDecoratorContext<This, Value> helper type.

For example

function VueReactiveDataField(
  _: undefined,
  // `unknown` if you don't care about the type of the class where decorated
  // property belongs
  // `string` so that you can only decorate string properties
  context: ClassFieldDecoratorContext<unknown, string>
): void {
  console.log(_, context);
}

@VueComponentOptions
export default class ReactiveStateExperimentalSample {
  @VueReactiveDataField
  protected exampleReactiveField: string = "Experimental sample works fine";
}

Or make it generic

function VueReactiveDataField<
  This, 
  // Will only work for properties of type `string`, `number` or `string | number` (or `never` but that's boring)
  Value extends string | number
>(
  _: undefined,
  context: ClassFieldDecoratorContext<This, Value>
): void {
  console.log(_, context);
}

@VueComponentOptions
export default class ReactiveStateExperimentalSample {
  @VueReactiveDataField
  protected exampleReactiveField: string = "Experimental sample works fine";
}