TypeScript 参数装饰器怎么用

在写前端代码时,你有没有遇到过这样的情况:一个函数的参数需要加权限校验,另一个函数的参数要做格式转换,要是每个函数都重复写这些逻辑,代码会越来越乱,维护起来特别麻烦。

其实TypeScript里有个叫“参数装饰器”的东西,就能帮我们解决这个重复代码的问题,它就像给函数参数贴个“标签”,让代码更整洁、更易维护。

TypeScript 参数装饰器怎么用

先搞懂:什么是参数装饰器?

简单来说,参数装饰器是一个作用在函数参数上的特殊函数,不是作用在整个函数,也不是作用在类。它的核心作用就是在不修改原函数代码的前提下,给参数添加额外的逻辑——比如校验、转换、日志记录这些,就像给水杯套个防烫套,水杯本身没改,但拿的时候不会烫手。

举个生活化的例子:你去咖啡店点单,店员给咖啡杯套了个“隔热套”,这个“隔热套”就相当于参数装饰器,咖啡杯(原参数)还是那个杯子,但加了套之后拿的时候更方便(多了防烫功能)。

怎么用?先搞定2个前提

要写参数装饰器,得先做2件小事,不然代码跑不起来:

第一,开启TypeScript的装饰器功能。在项目的tsconfig.json里,把experimentalDecorators设为true,这就像给手机开了“装饰器应用权限”;

第二,装饰器函数的格式要对,它会自动收到3个参数:目标对象(如果是类方法的参数,就是这个类的原型)、方法名、参数在函数里的位置序号,不用手动传。

写个实用例子:给参数加必填校验

很多时候我们需要函数参数不能是空,比如用户提交地址时,“收货人姓名”不能空。用参数装饰器就能统一写校验逻辑,不用每个函数都写if(!name) throw...。

我们先写一个Required装饰器:

`typescript

function Required(target: any, methodName: string, paramIndex: number) {

// 这里加校验逻辑:当函数被调用时,检查这个位置的参数是不是空

console.log(给${methodName}方法的第${paramIndex}个参数加了必填校验);

}

`

然后在函数里用它:

`typescript

class User {

// 给第1个参数加Required装饰器,注意位置是@Required,在参数前面

saveUser(@Required name: string, age: number) {

console.log(保存用户:姓名${name},年龄${age});

}

}

`

现在调用saveUser试试:

  • 当传saveUser("张三", 25)时,控制台会打印校验日志,函数正常执行;
  • 当传saveUser("", 25)时,装饰器的逻辑会触发(虽然上面的例子只打了日志,实际可以改成抛出错误),提醒你姓名不能为空,不用修改原saveUser函数的代码。

进阶一点:带参数的装饰器更灵活

刚才的Required是固定校验,要是想校验不同的参数,比如“姓名长度不能少于2”“手机号格式正确”,可以写带参数的装饰器,就像给隔热套选不同厚度,适配不同需求。

比如写一个MinLength装饰器,用来限制参数的最小长度:

`typescript

// 这里加个参数length,就是给装饰器传值,返回真正的装饰器函数

function MinLength(length: number) {

return function(target: any, methodName: string, paramIndex: number) {

console.log(${methodName}方法的第${paramIndex}个参数,要求最小长度${length});

}

}

`

用的时候只要传需要的长度就行:

`typescript

class User {

// 姓名最少2个字符

saveUser(@MinLength(2) name: string, age: number) {}

// 手机号最少11个字符

savePhone(@MinLength(11) phone: string) {}

}

`

这样同一个装饰器,能适配不同参数的校验需求,不用重复写函数。

注意这2个小坑

用参数装饰器时,要避开两个常见问题:

第一,它只作用在类方法的参数上,普通函数的参数不能用,就像隔热套只能套在带把手的水杯上,不能套在一次性纸杯上;

第二,装饰器的执行时机是“类定义的时候”,不是函数调用的时候,刚才例子里的日志,是在你定义User类时就会打印,不是调用saveUser时,这点要搞清楚,别和函数执行时的逻辑搞混。

其实参数装饰器的本质,就是把“和业务无关的通用逻辑”从函数里抽出来,统一用装饰器管理,让业务代码只写核心逻辑,不会被重复的校验、日志打乱,就像把水杯的防烫、防漏功能都用配套的套子实现,不用每个杯子单独做这些设计,代码自然更清爽。

上一篇 TypeScript zod 怎么用