繁体   English   中英

通过 TypeScript 中的装饰器向类添加属性

[英]Adding properties to a class via decorators in TypeScript

在 TypeScript 的装饰器参考页面上,有一段代码片段说明了如何使用类装饰器覆盖构造函数:

function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

@classDecorator
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

并在日志中:

class_1 {
  property: 'property',
  hello: 'override',
  newProperty: 'new property' }

到目前为止,一切都很好。 但是尝试通过点符号访问newProperty失败:

类型“Greeter”上不存在属性“newProperty”。ts(2339)

错误并且它没有在 VS Code 的提示中列出。 可以通过括号表示法访问它,但 TS 警告说

元素隐式具有“任何”类型,因为类型“Greeter”没有索引签名。ts(7017)

我错过了什么吗? 如何以类型安全的方式通过装饰器添加新属性? 我想像普通的类成员一样拥有普通的编译器支持。

设计的装饰器不能改变类的类型。 这仍在讨论中,并且在装饰器提案最终确定之前, 团队似乎不会改变行为。 你可以使用 mixins 来完成这个任务(阅读ts 中的 mixins

使用 mixins 的代码看起来像:

function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

const Greeter = classDecorator(class {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
});
type Greeter = InstanceType<typeof Greeter> // have the instance type just as if we were to declare a class

console.log(new Greeter("world").newProperty);
function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}
interface classInterface {
    newProperty: string;
    hello: string;
}

//trick
interface Greeter extends classInterface { };

@classDecorator
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}
const b = new Greeter();
console.log(b.newProperty);

看来我们可以使用接口技巧来解决问题。 技巧参考: https ://stackoverflow.com/a/52373394/4831179

我能找到的最佳解决方案是:

export function classDecorator<T extends { new(...args: any[]): {} }>(constructor: T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

class Greeter {
  property = "property";
  hello: string;
  constructor(m: string) {
    this.hello = m;
  }
}

注意:这不是最优的,因为它使Greeter.name返回一个空字符串! 该线程中的其他答案也是如此,所以我仍在寻找解决方案。

不是直接的解决方案,而是避免装饰器限制的解决方法:在某些情况下,可以将装饰器替换为可以正确继承类型的普通类。

class ClassDecorator {
        newProperty = "new property";
        hello = "override";
}

class Greeter extends ClassDecorator {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM