今天优化博客的时候,想优化表的更新时间字段,用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是没做处理的。

评论

0 / 800
全部评论()