使用装饰器包装类的过程会导致超类无法访问这些类'属性。为什么呢?
我有一些代码:
以下是代码:
function wrap(target: any) {
// the new constructor
var f: any = function (...args) {
return new target();
}
f.prototype = target.prototype;
return f;
}
@wrap
class Base {
prop: number = 5;
}
class Extended extends Base {
constructor() {
super()
}
}
var a = new Extended()
console.log(new Extended().prop) // I'm expecting 5 here, but I get undefined.
我确信这是一般原型的一些细微差别,或者是TypeScript处理它们的具体方式,我不理解。
答案 0 :(得分:13)
这段代码works对我来说:
function logClass(target: any) {
// save a reference to the original constructor
var original = target;
// the new constructor behaviour
var f : any = function (...args) {
console.log("New: " + original.name);
return original.apply(this, args)
}
// copy prototype so intanceof operator still works
f.prototype = original.prototype;
// return new constructor (will override original)
return f;
}
@logClass
class Base {
prop: number = 5;
}
class Extended extends Base {
constructor() {
super()
}
}
var b = new Base()
console.log(b.prop)
var a = new Extended()
console.log(a.prop)
答案 1 :(得分:3)
其他答案中的评论抱怨代码不起作用
实际上,它有效,但不适用于jsFiddle ...
这是jsFiddle中代码生成的问题(可能使用过时版本的TypeScript)
上面的代码适用于TypeScript 2.7.2(使用Node运行)。
所以这基本上是pablorsk答案中的代码(除了不需要返回实例),我只是添加了完整的类型来取悦更严格的TSLint ...
function logClass<T extends { new(...args: any[]): {} }>(): any {
type Ctor = new (...args: any[]) => T;
return (target: T): Ctor => {
// Save a reference to the original constructor
const Original = target;
// the new constructor behaviour
let decoratedConstructor: any = function (...args: any[]): void {
console.log("Before construction:", Original);
Original.apply(this, args);
console.log("After construction");
};
// Copy prototype so intanceof operator still works
decoratedConstructor.prototype = Original.prototype;
// Copy static members too
Object.keys(Original).forEach((name: string) => { decoratedConstructor[name] = (<any>Original)[name]; });
// Return new constructor (will override original)
return decoratedConstructor;
};
}
@logClass()
class Base {
prop = 5;
constructor(value: number) {
console.log("Base constructor", value);
this.prop *= value;
}
foo() { console.log("Foo", this.prop); }
static s() { console.log("Static s"); }
}
class Extended extends Base {
constructor(init: number) {
super(init);
console.log("Extended constructor", init);
}
bar() { console.log("Bar", this.prop); }
}
const b = new Base(2);
console.log("Base", b instanceof Base);
b.foo();
Base.s();
const e = new Extended(5);
console.log("Extended", e instanceof Base, e instanceof Extended);
e.bar();
[编辑]还添加了一行复制静态成员,否则在调用静态方法时,装饰类会抛出错误。
答案 2 :(得分:3)
这是使用最新TS(3.2.4)的更现代的方法。下面还使用了装饰器工厂模式,因此您可以传递属性:
function DecoratorName(attr: any) {
return function _DecoratorName<T extends {new(...args: any[]): {}}>(constr: T){
return class extends constr {
constructor(...args: any[]) {
super(...args)
console.log('Did something after the original constructor!')
console.log('Here is my attribute!', attr.attrName)
}
}
}
}
有关更多信息,请参见此处:https://www.typescriptlang.org/docs/handbook/decorators.html#class-decorators
答案 3 :(得分:2)
如果您喜欢run code after and before constructor() with a decorator:
function ClassWrapper() {
return function(target: any) {
// save a reference to the original constructor
var original = target;
// the new constructor behaviour
var f: any = function (...args) {
console.log('ClassWrapper: before class constructor', original.name);
let instance = original.apply(this, args)
console.log('ClassWrapper: after class constructor', original.name);
return instance;
}
// copy prototype so intanceof operator still works
f.prototype = original.prototype;
// return new constructor (will override original)
return f;
};
}
@ClassWrapper()
export class ClassExample {
public constructor() {
console.info('Running ClassExample constructor...');
}
}
let example = new ClassExample();
/*
CONSOLE OUTPUT:
ClassWrapper: before class constructor ClassExample
Running ClassExample constructor...
ClassWrapper: after class constructor ClassExample
*/
答案 4 :(得分:1)
使用ES2015代理覆盖构造函数的解决方案:
function wrap(target: any) {
return new Proxy(target, {
construct(clz, args) {
console.log(`Constructing ${target.name}`);
return Reflect.construct(clz, args);
}
});
}
@wrap
class Base {
prop: number = 5;
}
class Extended extends Base {
constructor() {
super()
}
}
var a = new Extended()
console.log(new Extended().prop);