Intro
This time, I will try decorators.
At first I wanted to implement init only setter property of C# in TypeScript.
As a result, I couldn't do that in this time.
Because the decorators are executed only on runtime.
So I just tried using them in this time.
Environments
- TypeScript ver.4.4.3
- Webpack ver.5.56.0
- webpack-cli ver.4.8.0
About decorators
I think the decorators are special kinds of functions for classes and class members.
I can't use them for functions, enums, and etc.
// Compile error: Decorators are not valid here
@message("Hello World")
export function funcSample() {
}
I can add decorators into classes, methods, properties, accessors, and paramters.
They are separated by their arguments.
main.page.ts
import { Sample } from "./sample";
function init(): void {
const s = new Sample();
s.userName = 'Masanori';
s.greet('Hello!');
}
init();
sample.ts
import { classDecorator, methodDecorator, methodDecoratorFactory } from "./decoratorSample";
// Class decorators
@classDecorator
export class Sample
{
private _userName = '';
// Accessor decorators(get/set)
// as same as the method decorators.
@methodDecorator
public get userName() {
return this._userName;
}
public set userName(value: string) {
this._userName = value;
}
public constructor() {
console.log("Hello constructor");
}
// Method decorators
@methodDecorator
// use factory functions to add any arguments
@methodDecoratorFactory("Hello world!")
public greet(message: string): void {
console.log('greet');
console.log(`${this._userName}: ${message}`);
}
}
decoratorSample.ts
export function classDecorator(constructor: Function): void {
console.log("classDecorator");
console.log(constructor);
}
export function methodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log('methodDecorator');
console.log(target);
console.log(propertyKey);
console.log(descriptor);
}
export function methodDecoratorFactory(args: string) {
console.log('methodDecoratorFactory');
console.log(args);
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) =>
methodDecorator(target, propertyKey, descriptor);
}
Result
methodDecorator
{constructor: ƒ, greet: ƒ}
userName
{enumerable: false, configurable: true, get: ƒ, set: ƒ}
methodDecoratorFactory
Hello world!
methodDecorator
{constructor: ƒ, greet: ƒ}
greet
{writable: true, enumerable: false, configurable: true, value: ƒ}
methodDecorator
{constructor: ƒ, greet: ƒ}
greet
{writable: true, enumerable: false, configurable: true, value: ƒ}
classDecorator
class Sample {
_userName = '';
get userName() {
return this._userName;
}
set userName(value) {
this._userName = value;
}
constructor() {
console.log…
Hello constructor
greet
Masanori: Hello!
Accessing or modifying classes and class members
For example, I can call caller methods from the decorators.
decoratorSample.ts
export function classDecorator(constructor: Function): void {
console.log("classDecorator");
// call caller methods
console.log(constructor.prototype['greet']());
}
export function methodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
console.log('methodDecorator');
// "target" is instance of the "Sample".
console.log(target);
}
And I can modify targets like below.
decoratorSample.ts
...
export function ModClassDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
console.log("ModClassDecorator");
return class extends constructor {
addedText = "added";
}
}
...
I must use generics to do this.
If I don't use generics and set the argument type as any, I will get an error.
decoratorSample.ts
...
export function ModClassDecorator2(constructor: any) {
console.log("ModClassDecorator2");
return class extends constructor {
addedText = "added";
}
}
...
Top comments (0)