今天优化博客的时候,想优化表的更新时间字段,用typeorm写的文章实体类继承的基类使用了装饰器,然后想在子类中覆盖,发现在ts中无法覆盖父类装饰器的问题。
普通的继承
// test.ts
// tsc test.ts --target ES5
class Super {
test() {
console.log('Super test');
}
}
class Test extends Super {
test() {
console.log('Test test');
}
}
再看看父类带装饰器的
// testDec.ts
// tsc testDec.ts --target ES5 --experimentalDecorators
const fnList: Function[] = [];
function D(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
// 在babel的网站编译的是target包含key,descriptor
if (target.descriptor) {
descriptor = target.descriptor;
}
fnList.push(descriptor.value);
}
class Super {
@D
test() {
console.log('Super test');
}
}
class Test extends Super {
test() {
console.log('Test test');
}
}
fnList[0](); // Super test
装饰器可以分为两类:一类是没有副作用的类似防抖截流装饰器,类似于函数式编程,不依赖外部变量;一类是有副作用的类似于做标记的功能,标记到某个地方然后使用,依赖外部变量。
这代码咋看一下是没毛病,但是用fnList收集模拟映射,可以看出fnList已经push过父类的方法了。
再看看编译后的js
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var fnList = [];
function D(target, propertyKey, descriptor) {
// 在babel的网站编译的是target包含key,descriptor
if (target.descriptor) {
descriptor = target.descriptor;
}
fnList.push(descriptor.value);
}
var Super = /** @class */ (function () {
function Super() {
}
Super.prototype.test = function () {
console.log('Super test');
};
// (2)
__decorate([
D
], Super.prototype, "test", null);
return Super;
}());
var Test = /** @class */ (function (_super) {
__extends(Test, _super);
function Test() {
return _super !== null && /* (1) */_super.apply(this, arguments) || this;
}
Test.prototype.test = function () {
console.log('Test test');
};
return Test;
}(Super));
fnList[0]();
可以看出到2这里就已经执行了装饰器,并记录下了test方法。
所以如果是防抖截流这类无副作用的装饰器在父类使用是没问题的,就算无法覆盖也不打紧;但如果是有记录或映射功能的有副作用的装饰器的话就要注意了。
其实如果映射时做了多次装饰时覆盖上一次,那么也没问题,但显然typeorm是没做处理的。
评论