S SmartDocs
시리즈: Typescript typescript 120 줄 · 업데이트 2025-12-27

05-decorators.ts

Typescript/src/02-intermediate/05-decorators.ts

// ============================================
// 05. Decorators
// ============================================

// Note: Enable "experimentalDecorators" in tsconfig.json

// Class Decorator
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
}

// Decorator Factory
function color(value: string) {
  return function (constructor: Function) {
    console.log(`Applying color ${value} to ${constructor.name}`);
  };
}

@color("red")
class Car {
  brand: string = "Toyota";
}

// Method Decorator
function enumerable(value: boolean) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    descriptor.enumerable = value;
  };
}

class Greeter2 {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }

  @enumerable(false)
  greet() {
    return "Hello, " + this.greeting;
  }
}

// Property Decorator
function format(formatString: string) {
  return function (target: any, propertyKey: string) {
    console.log(`Formatting ${propertyKey} with ${formatString}`);
  };
}

class User {
  @format("uppercase")
  name: string = "Alice";
}

// Logging Decorator
function log(target: any, propertyName: string, descriptor: PropertyDescriptor) {
  const method = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${propertyName} with`, args);
    const result = method.apply(this, args);
    console.log(`Result:`, result);
    return result;
  };
}

class Calculator {
  @log
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(5, 3); // Logs: Calling add with [5, 3], Result: 8

// Validation Decorator
function validate(min: number, max: number) {
  return function (target: any, propertyKey: string) {
    let value: number;

    const getter = () => value;
    const setter = (newVal: number) => {
      if (newVal < min || newVal > max) {
        throw new Error(`Value must be between ${min} and ${max}`);
      }
      value = newVal;
    };

    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter,
    });
  };
}

class Product {
  @validate(0, 100)
  price: number = 0;
}

const product = new Product();
product.price = 50; // OK
// product.price = 150; // Error: Value must be between 0 and 100

export { Greeter, Car, Calculator, Product };

관련 글