类装饰器应用于类构造函数,可以修改、替换或扩展类定义。类装饰器在类声明时被调用,接收类的构造函数作为唯一参数。
类装饰器是一个函数,接收构造函数作为参数。
function sealed(target: any) {
console.log(`密封 ${target.name}`)
Object.seal(target)
Object.seal(target.prototype)
}
@sealed
class User {
constructor(public name: string) {}
}
装饰器在类定义时立即执行。
类装饰器可以修改类的原型。
function addMethod(target: any) {
target.prototype.greet = function () {
return `你好,我是 ${this.name}`
}
}
@addMethod
class User {
constructor(public name: string) {}
}
const user = new (User as any)("张三")
console.log(user.greet())
类装饰器可以返回一个新的类,完全替换原有类。
function extend<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
createdAt = new Date()
id = Math.random().toString(36).substr(2, 9)
}
}
@extend
class User {
constructor(public name: string) {}
}
const user = new (User as any)("张三")
console.log(user.name)
console.log(user.id)
console.log(user.createdAt)
类装饰器可以接收参数。
function setAge(age: number) {
return function <T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
age = age
}
}
}
@setAge(25)
class User {
constructor(public name: string) {}
}
const user = new (User as any)("张三")
console.log(user.age)
类装饰器可以实现单例模式。
function singleton<T extends { new (...args: any[]): {} }>(constructor: T) {
let instance: any
return class extends constructor {
constructor(...args: any[]) {
if (instance) {
return instance
}
super(...args)
instance = this
}
}
}
@singleton
class Database {
constructor(public host: string) {
console.log("连接数据库")
}
}
const db1 = new (Database as any)("localhost")
const db2 = new (Database as any)("localhost")
console.log(db1 === db2)
类装饰器可以添加日志功能。
function logged(target: any) {
const original = target
const newConstructor: any = function (...args: any[]) {
console.log(`创建 ${original.name} 实例`)
console.log(`参数: ${JSON.stringify(args)}`)
return new original(...args)
}
newConstructor.prototype = original.prototype
return newConstructor
}
@logged
class User {
constructor(public name: string, public age: number) {}
}
const user = new (User as any)("张三", 25)
console.log(user.name)
类装饰器可以实现混合模式。
interface Serializable {
serialize(): string
}
function serializable(target: any) {
target.prototype.serialize = function () {
return JSON.stringify(this)
}
}
@serializable
class User {
constructor(public name: string, public age: number) {}
}
const user = new (User as any)("张三", 25)
console.log((user as any).serialize())
类装饰器常用于依赖注入框架。
type Constructor<T = any> = new (...args: any[]) => T
const container = new Map<string, any>()
function Injectable(key: string) {
return function <T extends Constructor>(target: T) {
container.set(key, new target())
return target
}
}
function Inject(key: string) {
return function (target: any, propertyKey: string) {
Object.defineProperty(target, propertyKey, {
get: () => container.get(key)
})
}
}
@Injectable("logger")
class Logger {
log(message: string) {
console.log(`[LOG] ${message}`)
}
}
@Injectable("userService")
class UserService {
@Inject("logger")
logger!: Logger
getUser(id: number) {
this.logger.log(`获取用户 ${id}`)
return { id, name: "张三" }
}
}
const userService = container.get("userService") as UserService
userService.getUser(1)
类装饰器应用于类构造函数,可以修改、替换或扩展类定义。类装饰器接收构造函数作为唯一参数,可以返回一个新的类。类装饰器可以实现单例模式、日志记录、混合模式等功能。装饰器工厂可以让类装饰器接收参数。类装饰器在依赖注入框架中广泛使用。