当前位置: 首页 > 知识库问答 >
问题:

如何实现打字稿装饰器?

饶谦
2023-03-14

TypeScript 1.5现在有了装饰器

有人能提供一个简单的例子来演示实现装饰器的正确方法,并描述可能有效的装饰器签名中的参数意味着什么吗?

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
declare type ParameterDecorator = (target: Function, propertyKey: string | symbol, parameterIndex: number) => void;

此外,在实现decorator时,是否应该记住任何最佳实践注意事项?

共有3个答案

仇高韵
2023-03-14
class Foo {
  @consoleLogger 
  Boo(name:string) { return "Hello, " + name }
}
  • 目标:在上述情况下,类的原型是“Foo”
  • propertyKey:调用的方法的名称,在上述情况下为“Boo”
  • 描述符:对象描述=

您可以实现将每次调用记录到控制台的功能:

function consoleLogger(target: Function, key:string, value:any) 
{
  return value: (...args: any[]) => 
  {
     var a = args.map(a => JSON.stringify(a)).join();
     var result = value.value.apply(this, args);
     var r = JSON.stringify(result);

     console.log('called method' + key + ' with args ' + a + ' returned result ' + r);

     return result;
  }     
}
段干博明
2023-03-14

我在其他答案中没有看到一件重要的事情:

如果我们想自定义如何将装饰器应用于声明,我们可以编写装饰器工厂。装饰器工厂只是一个函数,它返回装饰器将在运行时调用的表达式。

// This is a factory, returns one of ClassDecorator,
// PropertyDecorator, MethodDecorator, ParameterDecorator
function Entity(discriminator: string):  {
    return function(target) {
        // this is the decorator, in this case ClassDecorator.
    }
}

@Entity("cust")
export class MyCustomer { ... }

查看TypeScript手册装饰器一章。

邢卓
2023-03-14

最后,我和装饰师玩得很开心,并决定在任何文档发布之前,为任何想利用这一点的人记录我的想法。如果您看到任何错误,请随时编辑。

  • 装饰器在声明类时调用,而不是在实例化对象时调用。
  • 可以在同一个类/属性/方法/参数上定义多个装饰器。
  • 构造函数上不允许使用装饰器。

有效的装饰器应为:

  1. 可分配给其中一种装饰器类型(ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator

参考文献

实施参数

  • 目标:类的原型(对象)

使用:

class MyClass {
    @log
    myMethod(arg: string) { 
        return "Message -- " + arg;
    }
}

实施:

function log(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
    const originalMethod = descriptor.value; // save a reference to the original method

    // NOTE: Do not use arrow syntax here. Use a function expression in 
    // order to use the correct value of `this` in this method (see notes below)
    descriptor.value = function(...args: any[]) {
        // pre
        console.log("The method args are: " + JSON.stringify(args));
        // run and store result
        const result = originalMethod.apply(this, args);
        // post
        console.log("The return value is: " + result);
        // return the result of the original method (or modify it before returning)
        return result;
    };

    return descriptor;
}

输入:

new MyClass().myMethod("testing");

输出:

方法参数为:[“测试”]

返回值为:Message--testing

注意事项:

  • 设置描述符值时不要使用箭头语法。如果您这样做,this的上下文将不是实例的上下文。
  • 修改原始描述符比通过返回新描述符覆盖当前描述符更好。这允许您使用多个装饰器来编辑描述符,而不会覆盖另一个装饰器所做的。这样做允许您同时使用@enumerable(false)@log之类的东西(示例:坏vs好)
  • 有用的:Type属性描述符的类型参数可用于限制装饰器可以放置哪些方法签名(方法示例)或访问器签名(访问器示例)。

使用参数时,必须声明一个带有装饰器参数的函数,然后返回一个带有示例签名且没有参数的函数。

class MyClass {
    @enumerable(false)
    get prop() {
        return true;
    }
}

function enumerable(isEnumerable: boolean) {
    return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
        descriptor.enumerable = isEnumerable;
        return descriptor;
    };
}

类似于方法装饰器,但有一些区别:

  • 它的目标参数是构造函数本身,而不是原型
@isTestable
class MyClass {}

实现参数:

  • 目标:装饰器声明的类(TFunction扩展Function)。

示例用法:使用元数据api存储类的信息。

class MyClass {
    @serialize
    name: string;
}

实施参数:

  • 目标:类的原型(对象)

示例用法:创建一个序列化(“serializedName”)装饰器,并将属性名称添加到要序列化的属性列表中。

class MyClass {
    myMethod(@myDecorator myParameter: string) {}
}

实施参数:

  • 目标:类的原型(函数-似乎函数不再工作了。现在应该在此处使用任何对象,以便在任何类中使用装饰器。或者指定要限制它的类类型

简单示例

  • Memoize decorator-方法,获取/设置访问器decorator示例

 类似资料:
  • 有没有办法在VSCode中更改装饰器的语法高亮颜色?举个小例子: < code>@HostListener和< code>onMouseEnter都以相同的颜色突出显示。我想改变这一切。到目前为止,我已经尝试使用< code > " editor . tokencolorsumptions ":{ " functions ":" somecolor here " } } ,但是这同时改变了装饰器和

  • 问题内容: 问题是创建现有对象的动态增强版本。 我无法修改的。相反,我必须: 子类化 将现有对象包装在新对象中 将所有原始方法调用委托给包装的对象 实现另一个接口定义的所有方法 要添加到现有对象的接口是: 使用Byte Buddy,我设法继承了类并实现了我的接口。问题是委派给包装的对象。我发现做到这一点的唯一方法是使用反射速度太慢(我在应用程序上负担很重,性能至关重要)。 到目前为止,我的代码是:

  • 我正在努力寻找 有什么不同?

  • 我有一个小项目,用一个类包装另一个类的对象。修饰类实现了一个接口,但装饰类没有实现它。我很好奇它仍然是装饰模式还是其他模式,在我的项目中“装饰”类应该被称为包装器而不是装饰器。 我已经检查了iluwatar github存储库(https://github.com/iluwatar/java-design-patterns/tree/master/decorator/src/main/java/c

  • 问题内容: 考虑这个小例子: 哪个打印 为什么参数(应该是Test obj实例)没有作为第一个参数传递给装饰函数? 如果我手动进行操作,例如: 它按预期工作。但是,如果我必须事先知道某个函数是否装饰,它就破坏了装饰器的全部目的。这里的模式是什么,还是我误会了什么? 问题答案: tl; dr 您可以通过将类作为描述符并返回部分应用的函数来解决此问题,该函数从中应用对象作为参数之一,如下所示 实际问题

  • 我已经在我的.html文件中定义了这些: 然后在test.js: 但Typescript错误地指出:“找不到名称‘树’” 我也尝试编译与和放置在test.js文件的顶部,但它再次出错: