发布于 2026-01-05 9 阅读
0

理解 TypeScript 装饰器。

理解 TypeScript 装饰器。

JavaScript 是一门非常棒的编程语言。而 TypeScript 在弥补 JavaScript 的不足方面做得非常出色。它不仅添加了类型系统,还实现了一些 JavaScript 中尚不具备的额外功能,其中之一就是装饰器。

什么是装饰师?

装饰器在编程语言中由来已久。虽然定义各不相同,但简而言之,装饰器是 JavaScript 中的一种模式,用于包装某些代码以改变其行为。

在 JavaScript 和 TypeScript 中,这都是一项实验性功能。在 JavaScript 中,它目前仍处于第二阶段提案阶段,只能通过 Babel 等转译器使用。

我决定解释一下 TypeScript 装饰器,因为 TypeScript 已经将其标准化,而且两者本质上是一样的。

使用装饰器

这是一个非常简单的装饰器使用示例:

const myDecorator = (thing: Function) => {
    // return something
}

@myDecorator
class Thing {

}
Enter fullscreen mode Exit fullscreen mode

首先,我们定义一个函数myDecorator,然后Thing用装饰器“装饰”一个变量(在本例中是我们的类)。装饰器几乎可以返回任何东西,但大多数情况下,它用于设置类的属性等等。以下是一个实际示例:

const defaultGun = (gun: Function) => class extends gun {
    ammo = 10
}

@defaultGun
class Gun {

}
Enter fullscreen mode Exit fullscreen mode

现在,它将默认Gun具有一个属性。ammo

const gun = new Gun()
console.log(gun.ammo) // => 10
Enter fullscreen mode Exit fullscreen mode

装饰函数

我们还可以在类方法中使用装饰器。这次,装饰器需要三个参数。

const myDecorator = (parent: Function, prop: string, descriptor: PropertyDescriptor) => {
    // return something
}

class Gun {
    @myDecorator
    fire() {
        console.log('Firing in 3... 2... 1... 🔫')
    }
}
Enter fullscreen mode Exit fullscreen mode

第一个参数包含被装饰对象所在的类(在本例中Gun)。第二个参数是被装饰属性的名称(在本例中fire)。最后一个参数是属性描述符,它是以下代码的输出:Object.getOwnPropertyDescriptor(parent[prop])

特性

你也可以装饰属性。它与函数装饰器非常相似,只是没有第三个参数:

const myDecorator = (parent: Function, prop: string) => {
    // return something
}
Enter fullscreen mode Exit fullscreen mode

更多可以装饰的地方

你还可以装饰更多地方。请查阅文档了解更多信息。

用例

装饰器有很多用途。我们在这里介绍其中的一些。

计算性能

class Gun {
    @time
    fire() {
        console.log('Firing in 3... 2... 1... 🔫')
    }
}
Enter fullscreen mode Exit fullscreen mode

time可能是一个计算执行时间的函数。

装饰工厂

装饰器也可以是工厂函数,它会返回一个实际的装饰器函数。当你希望装饰器接受参数时,这非常有用。

// The decorator factory
const change = value => {
    // The factory will return a new handler
    return (target, prop) => {
        // We replace the old value with a new one
        Object.defineProperty(target, prop, {value})
    }
}
Enter fullscreen mode Exit fullscreen mode

然后,在进行“装饰”时,我们只需要像装饰函数一样进行装饰即可:

class Gun {
    @change(20)
    ammo = 10
}

const gun = new Gun();
console.log(gun.ammo) // => 20
Enter fullscreen mode Exit fullscreen mode

一个实际例子:错误处理

让我们运用所学知识来解决一个现实世界的问题。

class Gun {
    ammo = 0

    fireTwice() {
        console.log('Firing in 3... 2... 1... 🔫')
    }
}
Enter fullscreen mode Exit fullscreen mode

要发射两次子弹,至少需要两发子弹。我们可以使用装饰器来检查这一点:

const minAmmo = (ammo: number) => (
    target: Object,
    prop: string,
    descriptor: PropertyDescriptor
) => {
    const original = descriptor.value;

    descriptor.value = function (...args) {
        if (this.ammo >= ammo) original.apply(this);
        else console.log('Not enough ammo!');
    }

    return descriptor;
}
Enter fullscreen mode Exit fullscreen mode

minAmmo是一个工厂装饰器,它接受一个参数ammo,即所需的最小弹药量。

我们可以在Gun类中实现它。

class Gun {
    ammo = 0

    @minAmmo(2)
    fireTwice() {
        console.log('Firing in 3... 2... 1... 🔫')
    }
}
Enter fullscreen mode Exit fullscreen mode

现在如果你跑fireTwice(),它不会开火,因为我们没有足够的弹药。

好处在于我们可以直接复用这段代码,而无需重写 if 语句。假设我们需要一个fireOnce方法,我们也可以轻松地实现它。

class Gun {
    ammo = 0

    @minAmmo(2)
    fireTwice() {
        console.log('Firing twice in 3... 2... 1... 🔫')
    }

    @minAmmo(1)
    fireOnce() {
        console.log('Firing once in 3... 2... 1... 🔫')
    }
}
Enter fullscreen mode Exit fullscreen mode

这种装饰器在身份验证、授权以及其他各种功能上都非常有用。


喜欢这篇文章吗?❤️ 点赞。爱不释手吗?🦄 点赞。

如果你想让更多人了解这件事,请在推特上分享。

文章来源:https://dev.to/siddharthshyniben/understanding-typescript-decorators-3ifc