[{"data":1,"prerenderedAt":384},["ShallowReactive",2],{"content:\u002Fposts\u002F2024\u002Fts-decorators":3,"surround:\u002Fposts\u002F2024\u002Fts-decorators":373},{"id":4,"title":5,"body":6,"canonical":353,"categories":354,"date":356,"description":353,"draft":357,"extension":358,"image":359,"meta":360,"navigation":361,"path":362,"permalink":353,"readingTime":363,"recommend":353,"references":353,"seo":368,"sitemap":369,"stem":370,"tags":371,"type":353,"updated":356,"__hash__":372},"content\u002Fposts\u002F2024\u002Fts-decorators.md","TypeScript 装饰器",{"type":7,"value":8,"toc":330},"minimark",[9,26,31,34,39,51,59,62,68,76,83,86,92,95,98,104,109,115,118,123,129,132,138,141,147,150,155,161,164,170,177,183,187,190,196,200,206,210,216,220,223,229,232,235,266,272,276,279,285,288,290,312,318],[10,11,12],"blockquote",{},[13,14,15],"p",{},[16,17,18,19],"strong",{},"代码来自",[20,21,25],"a",{"href":22,"rel":23},"https:\u002F\u002Fwww.houdunren.com",[24],"nofollow","后盾网",[13,27,28],{},[16,29,30],{},"装饰器为 ts 提供了强大的代码复用功能",[13,32,33],{},"使用装饰器需要在 tsconfig.json 中修改",[10,35,36],{},[13,37,38],{},"装饰器是试验性的功能，需要在配置文件中开启",[40,41,47],"pre",{"className":42,"code":44,"language":45,"meta":46},[43],"language-json","{\n  \"experimentalDecorators\": true,\n  \"emitDecoratorMetadata\": true,\n}\n","json","tsconfig.json",[48,49,44],"code",{"__ignoreMap":50},"",[52,53,55,56],"h2",{"id":54},"类装饰器-classdecorator","类装饰器 ",[48,57,58],{"code":58},"ClassDecorator",[13,60,61],{},"相当于在原型对象上添加属性",[13,63,64,67],{},[16,65,66],{},"类装饰器只有一个参数","，是构造函数。",[40,69,74],{"className":70,"code":72,"language":73,"meta":50},[71],"language-ts","const moveDecorator: ClassDecorator = (target: () => void) => {\n    console.log(target)\n    target.prototype.getPosition = (): { x: number, y: number } => {\n        return { x: 20, y: 20 }\n    }\n}\n\n@moveDecorator\nclass Player {}\n\n@moveDecorator\nclass Tank {}\n\nconst player = new Player()\nconsole.log(player.getPosition())\n","ts",[48,75,72],{"__ignoreMap":50},[52,77,79,80],{"id":78},"装饰器语法糖","装饰器语法糖 ",[48,81,82],{"code":82},"@",[13,84,85],{},"不使用语法糖，需要传递类到对应的函数中。使用语法糖不需要手动调用。",[40,87,90],{"className":88,"code":89,"language":73,"meta":50},[71],"const moveDecorator: ClassDecorator = (target: () => void) => {\n    console.log(target)\n    target.prototype.getPosition = (): { x: number, y: number } => {\n        return { x: 20, y: 20 }\n    }\n}\n\n\u002F\u002F 不使用语法糖\nclass Player {}\nmoveDecorator(Player)\n\n\u002F\u002F 使用语法糖\n@moveDecorator\nclass Tank {}\n\nconst player = new Player()\nconsole.log(player.getPosition())\n",[48,91,89],{"__ignoreMap":50},[52,93,94],{"id":94},"装饰器叠加",[13,96,97],{},"可以使用多个装饰器",[40,99,102],{"className":100,"code":101,"language":73,"meta":50},[71],"const moveDecorator: ClassDecorator = (target: () => void) => {\n    target.prototype.getPosition = () => {\n        console.log(\"获取位置\")\n    }\n}\nconst MusicDecorator: ClassDecorator = (target: () => void) => {\n    target.prototype.playMusic = () => {\n        console.log(\"音乐播放\")\n    }\n}\n\n@moveDecorator\nclass Player {}\n\nconst player = new Player()\nplayer.getPosition()\n\n@MusicDecorator\n@moveDecorator\nclass Tank {}\n\nconst tank = new Tank()\ntank.playMusic()\ntank.getPosition()\n",[48,103,101],{"__ignoreMap":50},[105,106,108],"h3",{"id":107},"实例全局消息响应","实例：全局消息响应",[40,110,113],{"className":111,"code":112,"language":73,"meta":50},[71],"const MessageDecorator: ClassDecorator = (target: () => void) => {\n    target.prototype.sendMessage = (message: string, type: \"success\" | \"error\" = \"success\") => {\n        return {\n            message,\n            type,\n        }\n    }\n}\n\n@MessageDecorator\nclass LoginController {\n    login() {\n        console.log(\"登录业务处理\")\n        setTimeout(() => {\n            this.sendMessage(\"登录成功\")\n        }, 2000)\n    }\n}\nnew LoginController().login()\n",[48,114,112],{"__ignoreMap":50},[52,116,117],{"id":117},"装饰器工厂",[13,119,120],{},[16,121,122],{},"根据不同的条件返回不同的装饰器",[40,124,127],{"className":125,"code":126,"language":73,"meta":50},[71],"function MusicDecorator(type: string): ClassDecorator {\n    switch (type) {\n        case \"player\":\n            return (target: () => void) => {\n                target.prototype.playMusic = () => {\n                    console.log(\"play player music\")\n                }\n            }\n        case \"tank\":\n            return (target: () => void) => {\n                target.prototype.playMusic = () => {\n                    console.log(\"play tank music\")\n                }\n            }\n        default:\n            return (target: () => void) => {\n                target.prototype.playMusic = () => {\n                    console.log(\"play other music\")\n                }\n            }\n    }\n}\n\n@MusicDecorator(\"player\")\nclass Player {}\nnew Player().playMusic()\n\n@MusicDecorator(\"tank\")\nclass Tank {}\nnew Tank().playMusic()\n",[48,128,126],{"__ignoreMap":50},[52,130,131],{"id":131},"方法装饰器",[40,133,136],{"className":134,"code":135,"language":73,"meta":50},[71],"const ShowDecorator: MethodDecorator = (...args: any[]) => {\n    console.log(args)\n    \u002F**\n   打印参数：\n     [0]: 如果是静态函数就是构造函数，如果是普通方法就是其原型对象\n     [1]: 使用装饰器的方法名称\n     [2]: 方法属性的描述\n  [\n    User: {},\n    \"show\",\n    {\n      \"value\": [Function (anonymous)] \u002F\u002F 函数的内容\n      \"writable\": true,\n      \"enumerable\": false,\n      \"configurable\": true\n    }\n  ]\n     *\u002F\n}\nclass User {\n    @ShowDecorator\n    public show() {}\n}\n",[48,137,135],{"__ignoreMap":50},[13,139,140],{},"可以使用函数装饰器更改函数的内容",[40,142,145],{"className":143,"code":144,"language":73,"meta":50},[71],"const ShowDecorator: MethodDecorator = (...args: any[]) => {\n    console.log(args)\n    args[2].value = () => {\n        console.log(\"ShowDecorator changed\")\n    }\n}\nclass User {\n    @ShowDecorator\n    public show() {\n        console.log(\"show function \")\n    }\n}\n\nnew User().show() \u002F\u002F 打印 \"ShowDecorator changed\"，函数内容已经被更改\n",[48,146,144],{"__ignoreMap":50},[13,148,149],{},"上面那样使用数组接收后调用不是很直观，我们可以使用变量名接收方法装饰器参数",[13,151,152],{},[48,153,154],{"code":154},"const ShowDecorator: MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => { ... };",[40,156,159],{"className":157,"code":158,"language":73,"meta":50},[71],"const ShowDecorator: MethodDecorator = (\n    target: object,\n    propertyKey: string | symbol,\n    descriptor: PropertyDescriptor\n) => {\n    descriptor.value = () => {\n        console.log(\"ShowDecorator changed\")\n    }\n}\nclass User {\n    @ShowDecorator\n    public show() {\n        console.log(\"show function \")\n    }\n}\n\nnew User().show() \u002F\u002F 打印 \"ShowDecorator changed\"，函数内容已经被更改\n",[48,160,158],{"__ignoreMap":50},[13,162,163],{},"调用装饰器时，也可以更改静态方法的内容",[40,165,168],{"className":166,"code":167,"language":73,"meta":50},[71],"const ShowDecorator: MethodDecorator = (\n    target: object,\n    propertyKey: string | symbol,\n    descriptor: PropertyDescriptor\n) => {\n    descriptor.value = () => {\n        console.log(\"ShowDecorator changed\")\n    }\n}\nclass User {\n    @ShowDecorator\n    public static show() {\n        console.log(\"show function \")\n    }\n}\n\nUser.show() \u002F\u002F 打印 \"ShowDecorator changed\"，函数内容已经被更改\n",[48,169,167],{"__ignoreMap":50},[13,171,172,173,176],{},"调用 ",[48,174,175],{"code":175},"writable = true"," 控制方法不能重新声明",[40,178,181],{"className":179,"code":180,"language":73,"meta":50},[71],"const ShowDecorator: MethodDecorator = (\n    target: object,\n    propertyKey: string | symbol,\n    descriptor: PropertyDescriptor\n) => {\n    descriptor.value = () => {\n        console.log(\"ShowDecorator changed\")\n    }\n    descriptor.writable = false\n}\nclass User {\n    @ShowDecorator\n    public static show() {\n        console.log(\"show function \")\n    }\n}\n\nUser.show() \u002F\u002F 打印 \"ShowDecorator changed\"，函数内容已经被更改\nUser.show = () => {\n    console.log(\"重写show方法\")\n}\nUser.show()\n",[48,182,180],{"__ignoreMap":50},[105,184,186],{"id":185},"示例模拟代码高亮","示例：模拟代码高亮",[13,188,189],{},"可以先使用变量将函数内容保存起来，在自定义操作后直接调用保存的函数",[40,191,194],{"className":192,"code":193,"language":73,"meta":50},[71],"const HighlightDecorator: MethodDecorator = (\n    target: object,\n    propertyKey: string | symbol,\n    descriptor: PropertyDescriptor\n) => {\n    const method = descriptor.value\n    descriptor.value = () => {\n        return `\u003Cdiv style=\"background: red;\">${method()}\u003C\u002Fdiv>`\n    }\n}\nclass User {\n    @HighlightDecorator\n    public show() {\n        return \"js code \"\n    }\n}\nnew User().show()\n",[48,195,193],{"__ignoreMap":50},[105,197,199],{"id":198},"示例结合装饰器工厂实现延迟执行","示例：结合装饰器工厂实现延迟执行",[40,201,204],{"className":202,"code":203,"language":73,"meta":50},[71],"function SleepDecorator(times: number = 2000): MethodDecorator {\n    return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n        const method = descriptor.value\n        descriptor.value = () => {\n            setTimeout(() => {\n                method()\n            }, times)\n        }\n    }\n}\nclass User {\n    @SleepDecorator(3000)\n    public show() {\n        console.log(\"wxw\")\n    }\n}\nnew User().show()\n",[48,205,203],{"__ignoreMap":50},[105,207,209],{"id":208},"示例全局异常处理","示例：全局异常处理",[40,211,214],{"className":212,"code":213,"language":73,"meta":50},[71],"const ErrorDecorator: MethodDecorator = (\n    target: object,\n    propertyKey: string | symbol,\n    descriptor: PropertyDescriptor\n) => {\n    const method = descriptor.value\n\n    descriptor.value = () => {\n        try {\n            method()\n        }\n        catch (e) {\n            \u002F\u002F 函数中抛出的错误在这里进行处理\n            console.log(\"%c异常处理\", \"color: green;\")\n            console.log(`%c${e}`, \"color: red\")\n        }\n    }\n}\n\nclass User {\n    @ErrorDecorator\n    find() {\n        throw new Error(\"出错了\")\n    }\n}\nnew User().find()\n",[48,215,213],{"__ignoreMap":50},[105,217,219],{"id":218},"示例根据权限限制访问","示例：根据权限限制访问",[13,221,222],{},"可以根据传入的权限数组进行判断用户是否有访问权限",[40,224,227],{"className":225,"code":226,"language":73,"meta":50},[71],"interface UserType { name: string, isLogin: boolean, permissions: string }\nconst user = {\n    name: \"wxw\",\n    isLogin: true,\n    permissions: [\"admin\", \"member\"],\n}\nfunction AccessDecorator(keys: string[]): MethodDecorator {\n    return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n        const method = descriptor.value\n        const validate = () => keys.every(k => user.permissions.includes(k))\n        descriptor.value = () => {\n            \u002F\u002F 控制用户登录并且有权限才可访问\n            if (user.isLogin && validate() === true) {\n                console.log(\"验证通过\")\n                method()\n            }\n            else {\n                console.log(\"验证失败\")\n                return false\n            }\n        }\n    }\n}\n\nclass User {\n    @AccessDecorator([\"admin\"])\n    find() {\n        console.log(\"find function\")\n    }\n}\nnew User().find()\n",[48,228,226],{"__ignoreMap":50},[52,230,231],{"id":231},"属性装饰器",[13,233,234],{},"接收的参数",[236,237,238,251,260],"ul",{},[239,240,241,242,246,247,250],"li",{},"args",[243,244,245],"span",{},"0",": ",[48,248,249],{"code":249},"target"," 静态参数就是构造函数，普通参数就是其原型对象",[239,252,241,253,246,256,259],{},[243,254,255],{},"1",[48,257,258],{"code":258},"propertyKey"," 属性名称",[239,261,241,262,265],{},[243,263,264],{},"2",": undefined",[40,267,270],{"className":268,"code":269,"language":73,"meta":50},[71],"const PropDecorator: PropertyDecorator = (target: object, propertyKey: string | symbol) => {\n    console.log(target, propertyKey)\n}\nclass User {\n    public username: string\n}\n",[48,271,269],{"__ignoreMap":50},[105,273,275],{"id":274},"实例使用属性装饰器动态改变对象属性","实例：使用属性装饰器动态改变对象属性",[13,277,278],{},"将属性改为全部大写",[40,280,283],{"className":281,"code":282,"language":73,"meta":50},[71],"const UpperDecorator: PropertyDecorator = (target: object, propertyKey: string | symbol) => {\n    let value: string\n\n    \u002F\u002F 在这里使用Object.defineProperty对原数据进行更改\n    Object.defineProperty(target, propertyKey, {\n        get() {\n            return value.toUpperCase()\n        },\n        set(v) {\n            value = v\n        },\n    })\n}\n\nclass Article {\n    @UpperDecorator\n    public title: string | undefined\n}\n\nconst article = new Article()\narticle.title = \"article title\"\nconsole.log(article.title)\n",[48,284,282],{"__ignoreMap":50},[52,286,287],{"id":287},"参数装饰器",[13,289,234],{},[236,291,292,298,304],{},[239,293,241,294,246,296,250],{},[243,295,245],{},[48,297,249],{"code":249},[239,299,241,300,246,302,259],{},[243,301,255],{},[48,303,258],{"code":258},[239,305,241,306,246,308,311],{},[243,307,264],{},[48,309,310],{"code":310},"parameterIndex"," 参数所在的位置，从 0 开始计数",[40,313,316],{"className":314,"code":315,"language":73,"meta":50},[71],"const ParamDecorator: ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => {\n    console.log(target, propertyKey, parameterIndex)\n}\nclass User {\n    show(id: number, @ParamDecorator user: { name: string }) {}\n}\n",[48,317,315],{"__ignoreMap":50},[319,320,321,327],"alert",{},[322,323,324],"template",{"v-slot:title":50},[13,325,326],{},"装饰器执行顺序:",[13,328,329],{},"参数装饰器 -> 方法装饰器",{"title":50,"searchDepth":331,"depth":331,"links":332},4,[333,336,338,342,343,349,352],{"id":54,"depth":334,"text":335},2,"类装饰器 ClassDecorator",{"id":78,"depth":334,"text":337},"装饰器语法糖 @",{"id":94,"depth":334,"text":94,"children":339},[340],{"id":107,"depth":341,"text":108},3,{"id":117,"depth":334,"text":117},{"id":131,"depth":334,"text":131,"children":344},[345,346,347,348],{"id":185,"depth":341,"text":186},{"id":198,"depth":341,"text":199},{"id":208,"depth":341,"text":209},{"id":218,"depth":341,"text":219},{"id":231,"depth":334,"text":231,"children":350},[351],{"id":274,"depth":341,"text":275},{"id":287,"depth":334,"text":287},null,[355],"代码","2024-03-17 00:27:44",false,"md","https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002F67a188c8ab863-78.webp",{},true,"\u002Fposts\u002F2024\u002Fts-decorators",{"text":364,"minutes":365,"time":366,"words":367},"8 min read",7.475,448500,1495,{"title":5,"description":353},{"loc":362},"posts\u002F2024\u002Fts-decorators",[],"851xuHdbztbWx5jR9qi_VujlHMT1kHBB8i-r3NT-f0M",[374,379],{"title":375,"path":376,"stem":377,"date":378,"type":353,"children":-1},"TypeScript interface和type","\u002Fposts\u002F2024\u002Fts-interface-and-type","posts\u002F2024\u002Fts-interface-and-type","2024-03-17 00:27:25",{"title":380,"path":381,"stem":382,"date":383,"type":353,"children":-1},"TypeScript 命名空间","\u002Fposts\u002F2024\u002Fts-namespace","posts\u002F2024\u002Fts-namespace","2024-03-17 00:28:24",1789642592162]