TypeScript——装饰器、命名空间、混入、Reflect Metadata

本文详细介绍了TypeScript中的装饰器(包括类装饰器、方法装饰器和参数装饰器)、命名空间的作用以及混入技术。重点讲解了ReflectMetadataAPI的使用,展示了如何通过装饰器和元数据来扩展类和方法的功能。
摘要由CSDN通过智能技术生成

一、装饰器(Decorator)

主要用来扩展类和类的方法

1.类装饰器( ClassDecorator)

创建一个装饰器工厂函数:创建一个接受参数的函数,它将返回一个装饰器函数。装饰器函数将接收类的构造函数作为参数,并可以在装饰器函数内部访问类的属性和方法。

在类前使用装饰器:使用 @ 符号,后跟装饰器工厂函数的调用,将装饰器应用于类。

//target构造函数 
const base: ClassDecorator = (target: any) => {   
  console.log(target);
  target.prototype.__xiaowu = '琳'
  target.prototype.fn = () => {
    console.log('hello,world');
  }
}
// 第一种方法
@base
class Http {
}
const http: any = new Http()
// 第二种方法
base(Http) //向下兼容
http.fn()
console.log(http.__xiaowu);

2.方法装饰器 (MethodDecorator)

import 'reflect-metadata'
import axios from 'axios'
const Get = (url: string) => {
  const fn: MethodDecorator = (target, _: any, descriptor: PropertyDescriptor) => {
    const key = Reflect.getMetadata('key', target)
    axios.get(url).then(res => {
      descriptor.value(key ? res.data[key] : res.data)
    })
  }
  return fn
}
const Result = () => {
  const fn: ParameterDecorator = (target, key, index) => {
    console.log(target, key, index, "111"); //index为Result所在的位置
    Reflect.defineMetadata('key', 'result', target)
  }
  return fn
}
const Name: PropertyDecorator = (target, key) => {
  console.log(target, key);
}
class Http {
  @Name
  // 属性装饰器
  xiaoman: string
  constructor() {
    this.xiaoman = '小曼'
  }
  //方法装饰器
  @Get('https://api.apiopen.top/api/getHaoKanVideo?paage=0&size=10')
  //参数装饰器
  getList(@Result() data: any) {
    console.log(data, "data");
  }
  // @post() 同理
  // create() {
  // }
}
const http: any = new Http()
console.log(http);

3.参数装饰器 (ParameterDecorator)

//见上

4.参数装饰器 (PropertyDecorator)

//见上

5.装饰器工厂

定义一个装饰器工厂函数,它接受任意个参数,并返回一个装饰器函数。装饰器函数接受一个参数,即被装饰的类。

在装饰器函数内部,可以通过修改参数的原型对象来对类进行装饰。

const base = (name: string) => {
  // 函数柯里化,新增自己传进来的值,外面的函数接收自定义参数,里面的函数返回值
  // const fn: ClassDecorator = (target: any) => {
  //   target.prototype.aa = function () {
  //     console.log(name);
  //   };
  // }
  // return fn
  return function (target: any) {
    // 修改原型对象,添加一个greeting方法
    target.prototype.aa = function () {
      console.log(name);
    };
  }

}
@base('xiaoyu')
class Http {

}
const http: any = new Http()
http.aa()

二、命名空间(namespace)

在TypeScript中,命名空间(Namespace)是用来组织和管理代码的一种方式。可以将相似的功能或相关的类、接口、函数等放到同一个命名空间中,以便更好地组织和管理代码。

test.ts中
namespace Test {
  export let a = 1
  export const add = (a: number, b: number) => a + b
  export namespace Test2 {
    export let b = 14
  }
}
namespace Test {
  export let v = 2
}

//使用文件中
import { Test } from './test'
import a = Test.add
console.log(a(1, 2));

三、混入

1.对象混入

interface A {
  age: number
}
interface B {
  name: string
}
let a: A = {
  age: 18
}
let b: B = {
  name: '张灿'
}
// 1、 扩展运算符 浅拷贝,返回新的类型
let c = { ...a, ...b }
console.log(c, "c");
// 2、Object.assign 浅拷贝 返回交叉类型
let c1 = Object.assign({}, a, b)
console.log(c1);

2.类混入

是一种将多个类组合在一起创建一个新类的方法。它允许我们在不使用继承的情况下将类的功能组合在一起,以便在不同的类之间共享和重用代码。

class Logger {
  log(msg: string) {
    console.log(msg);
  }
}
class Html {
  render() {
    console.log('22222');
  }
}
class App {
  run() {
    console.log('run');
  }
}
type Custructor<T> = new (...args: any[]) => T
function pluginMinxins<T extends Custructor<App>>(base: T) {
  return class extends base {
    private Logger = new Logger()
    private Html = new Html()
    constructor(...args: any[]) {
      super(...args)
      this.Logger = new Logger()
      this.Html = new Html()
    }
    run(): void {
      this.Logger.log('run')
    }
    render() {
      this.Logger.log('render')
      this.Html.render()
      this.Logger.log('run')
    }
  }
}
const mixins = pluginMinxins(App)
const app = new mixins()
app.render() //输出render,2222.run

四、Reflect Metadata得API

使用Reflect.defineMetadata()时,需要在tsconfig.json中配置:

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

简单介绍下:Reflect.defineMetadata()是一个方法,用于定义元数据(metadata)。元数据是关于数据的数据,用于描述数据的特征和属性。在JavaScript中,元数据可以通过Reflect.defineMetadata方法添加到对象或函数上,并可以通过Reflect.getMetadata方法获取。

metadataKey: 用于存储和检索元数据的键;
metadataValue: 元数据的值;
target: 要在其上定义元数据的目标对象;
propertyKey: 目标对象上的属性;

import 'reflect-metadata'
 
// 元数据的命令式定义,定义对象或属性的元数据
Reflect.defineMetadata(metadataKey, metadataValue, target)
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)
 
// 检查对象或属性的原型链上是否存在元数据键
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
 
// 检查对象或属性是否存在自己的元数据键
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
 
// 获取对象或属性原型链上元数据键的元数据值
let result = Reflect.getMetadata(metadataKey, target)
let result = Reflect.getMetadata(metadataKey, target, propertyKey)
 
// 获取对象或属性的自己的元数据键的元数据值
let result = Reflect.getOwnMetadata(metadataKey, target)
let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey)
 
// 获取对象或属性原型链上的所有元数据键
let result = Reflect.getMetadataKeys(target)
let result = Reflect.getMetadataKeys(target, propertyKey)
 
// 获取对象或属性的所有自己的元数据键
let result = Reflect.getOwnMetadataKeys(target)
let result = Reflect.getOwnMetadataKeys(target, propertyKey)
 
// 从对象或属性中删除元数据
let result = Reflect.deleteMetadata(metadataKey, target)
let result = Reflect.deleteMetadata(metadataKey, target, propertyKey)
 
// 通过装饰器将元数据应用于构造函数
@Reflect.metadata(metadataKey, metadataValue)
class C {
  // 通过装饰器将元数据应用于方法(属性)
  @Reflect.metadata(metadataKey, metadataValue)
  method() {
  }
}

总结

参考链接:【TypeScript 教程】Reflect Metadata

最后:如果有问题或不理解的地方请大家指出,谢谢大家~

  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值