前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >十二个例子让你学会TypeScript装饰器

十二个例子让你学会TypeScript装饰器

原创
作者头像
星辰大海c
发布2023-11-08 16:38:26
发布2023-11-08 16:38:26
3170
举报
文章被收录于专栏:前端学习教程前端学习教程
WechatIMG588.png
WechatIMG588.png

理解 TypeScript 装饰器的关键是了解它们可以附加到类、方法、属性、参数等各种元素上,以修改它们的行为。以下是一些具体的 TypeScript 装饰器案例:

1. 类装饰器:添加元数据

类装饰器可以用来添加元数据或修改类的行为。例如,让我们创建一个用于标记类的装饰器,它会记录类的名称和一些元数据。

代码语言:typescript
复制
function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    className = constructor.name;
  };
}

@classDecorator
class MyClass {
  constructor(public data: string) {}
}

const instance = new MyClass("Hello");
console.log(instance.className); // 输出 "MyClass"

2. 方法装饰器:修改方法行为

方法装饰器可以用来修改方法的行为。以下示例演示如何创建一个方法装饰器,用于限制方法的执行次数。

代码语言:typescript
复制
function limitExecutions(limit: number) {
  return function (
    target: any,
    key: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value;
    let executions = 0;

    descriptor.value = function (...args: any[]) {
      if (executions < limit) {
        executions++;
        return originalMethod.apply(this, args);
      } else {
        console.log(`Method ${key} reached execution limit.`);
      }
    };

    return descriptor;
  };
}

class Example {
  @limitExecutions(2)
  execute() {
    console.log("Method executed.");
  }
}

const instance = new Example();
instance.execute(); // 输出 "Method executed."
instance.execute(); // 输出 "Method executed."
instance.execute(); // 输出 "Method reached execution limit."

3. 属性装饰器:添加元数据

属性装饰器用于添加元数据或修改属性的行为。以下示例创建一个属性装饰器,用于添加属性的描述信息。

代码语言:typescript
复制
function propertyDescription(description: string) {
  return function (target: any, key: string) {
    Reflect.defineMetadata("description", description, target, key);
  };
}

class Example {
  @propertyDescription("This is a sample property.")
  data: string;
}

const description = Reflect.getMetadata("description", Example.prototype, "data");
console.log(description); // 输出 "This is a sample property."

4. 参数装饰器:验证参数

参数装饰器可以用来验证方法的参数。以下示例演示如何创建一个参数装饰器,用于检查参数是否为正数。

代码语言:typescript
复制
function positiveNumber(target: any, key: string, index: number) {
  const originalMethod = target[key];

  target[key] = function (...args: any[]) {
    if (typeof args[index] !== "number" || args[index] <= 0) {
      console.log(`Invalid argument at position ${index}: ${args[index]}`);
    } else {
      return originalMethod.apply(this, args);
    }
  };
}

class Example {
  add(@positiveNumber a: number, @positiveNumber b: number) {
    return a + b;
  }
}

const instance = new Example();
instance.add(5, 10); // 输出 15
instance.add(-2, 10); // 输出 "Invalid argument at position 0: -2"

5. 计时装饰器:记录方法执行时间

代码语言:typescript
复制
function timing(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`Method ${key} took ${end - start} milliseconds.`);
    return result;
  };

  return descriptor;
}

class Timer {
  @timing
  slowOperation() {
    for (let i = 0; i < 10000000; i++) {}
  }
}

const timer = new Timer();
timer.slowOperation(); // 输出方法执行时间

6. 验证装饰器:验证输入参数

代码语言:typescript
复制
function validate(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    if (args.some(arg => typeof arg !== "number")) {
      console.error("Invalid argument type. Must be a number.");
      return;
    }
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

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

const calculator = new Calculator();
calculator.add(5, 10); // 输出 15
calculator.add(5, "10"); // 输出 "Invalid argument type. Must be a number."

7. 记录日志装饰器:记录方法调用日志

代码语言:typescript
复制
function log(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling method ${key} with arguments: ${args}`);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class Logger {
  @log
  logMessage(message: string) {
    console.log(message);
  }
}

const logger = new Logger();
logger.logMessage("Hello, World!"); // 输出方法调用日志

8. 身份验证装饰器:验证用户登录状态

代码语言:typescript
复制
function authenticate(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    // 检查用户是否已登录
    if (isUserLoggedIn()) {
      return originalMethod.apply(this, args);
    } else {
      console.error("Authentication failed. Please log in.");
    }
  };

  return descriptor;
}

class AuthenticatedApp {
  @authenticate
  accessSecureData() {
    console.log("Accessing secure data.");
  }
}

const app = new AuthenticatedApp();
app.accessSecureData(); // 输出 "Accessing secure data.",因为用户已登录

// 模拟用户未登录
function isUserLoggedIn() {
  return false;
}
app.accessSecureData(); // 输出 "Authentication failed. Please log in."

9. 路由装饰器:定义路由信息

代码语言:typescript
复制
function route(path: string) {
  return function (target: any, key: string, descriptor: PropertyDescriptor) {
    // 将路由信息存储在元数据中
    Reflect.defineMetadata("route", path, target, key);
  };
}

class RouterExample {
  @route("/home")
  displayHome() {
    // 显示主页
  }

  @route("/about")
  displayAbout() {
    // 显示关于页面
  }
}

// 获取路由信息
const homeRoute = Reflect.getMetadata("route", RouterExample.prototype, "displayHome");
console.log(homeRoute); // 输出 "/home"

10. 缓存装饰器:缓存方法的结果

代码语言:typescript
复制
function cache(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  const cache = new Map();

  descriptor.value = function (...args: any[]) {
    const cacheKey = JSON.stringify(args);
    if (cache.has(cacheKey)) {
      return cache.get(cacheKey);
    } else {
      const result = originalMethod.apply(this, args);
      cache.set(cacheKey, result);
      return result;
    }
  };

  return descriptor;
}

class CachedCalculator {
  @cache
  add(a: number, b: number) {
    return a + b;
  }
}

const calculator = new CachedCalculator();
console.log(calculator.add(2, 3)); // 输出 5
console.log(calculator.add(2, 3)); // 输出 5(从缓存中获取)

11. 日志装饰器:记录方法执行日志

代码语言:typescript
复制
function logMethod(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling method ${key} with arguments: ${JSON.stringify(args)}`);
    const result = originalMethod.apply(this, args);
    console.log(`Method ${key} returned: ${JSON.stringify(result)}`);
    return result;
  };

  return descriptor;
}

class LoggableClass {
  @logMethod
  performOperation(a: number, b: number) {
    return a + b;
  }
}

const loggable = new LoggableClass();
loggable.performOperation(3, 7); // 输出方法的执行日志

12. 跟踪装饰器:记录方法执行时间

代码语言:typescript
复制
function trackPerformance(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`Method ${key} took ${end - start} milliseconds to execute.`);
    return result;
  };

  return descriptor;
}

class PerformantClass {
  @trackPerformance
  timeConsumingOperation() {
    for (let i = 0; i < 100000000; i++) {}
  }
}

const performant = new PerformantClass();
performant.timeConsumingOperation(); // 输出方法的执行时间

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档