解決TypeScript裝飾器(decorators)和JavaScript裝飾器編譯出的代碼不一樣

Input Codejavascript

function observable() {}

class Example {
    @observable()
    toolbar = 'example';
}

export default Example;
複製代碼

JavaScript outputhtml

function observable() {}

var Example = (_dec = observable(), (_class = (_temp = function Example() {
  (0, _classCallCheck2["default"])(this, Example);
  (0, _initializerDefineProperty2["default"])(this, "toolbar", _descriptor, this);
}, _temp), (_descriptor = (0, _applyDecoratedDescriptor2["default"])(_class.prototype, "toolbar", [_dec], {
  configurable: true,
  enumerable: true,
  writable: true,
  initializer: function initializer() {
    return 'example';
  }
})), _class));

exports["default"] = Example;
複製代碼

TypeScript outputjava

function observable() {}

var Example = function Example() {
  (0, _classCallCheck2["default"])(this, Example);
  this.toolbar = 'example';
};

__decorate([observable(), __metadata("design:type", Object)], Example.prototype, "toolbar", void 0);

exports["default"] = Example;
複製代碼

咱們發現二者編譯出的裝飾器屬性代碼並不相同。react

如今咱們建立一個javascript類ExampleEnhance,繼承typescript類Example,並重寫裝飾器屬性toolbarwebpack

// This is javascript code, but class Example is typescript
class ExampleEnhance extends Example {
    @observable()
    toolbar = 'YY';
}
複製代碼

這時,咱們指望toolbar的值爲'YY',可是咱們發現它的值仍然是'example'。 怎麼辦? 咱們有沒有辦法讓TypeScriptJavaScript裝飾器屬性編譯出來的代碼相同呢?git

咱們從TypeScript官方獲得的回覆是github

TypeScript's decorators currently work differently from ES decorators, hence the experimental flag. If you need ES decorators you'll need to continue to process the code with Babel.web

Because Typescript's decorator specification is not quite the same as anyone else's, they are always transformed.typescript

You cannot do this right now unless you remove Typescript from the chain entirely. It always transforms decorators, leaving nothing left for Babel to transform.npm

所以,要讓二者編譯出相同的代碼,咱們必需要把typescript loader(好比awesome-typescript-loader, ts-loader)移除,而只使用babel來轉換這兩類代碼。這裏咱們須要引入@babel/plugin-transform-typescript插件來處理TypeScript

#配置babel

Install

npm install @babel/plugin-transform-typescript
複製代碼

babel.config.js

module.exports = {
    presets: ['@babel/preset-typescript', '@babel/preset-react', '@babel/preset-env', 'mobx'],
    plugins: [
        ['@babel/plugin-transform-typescript', { allowNamespaces: true }],
        // ... other
    ]
}
複製代碼

webpack.config.js

module.exports = {
    // ...
    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: ['.js', '.ts', '.tsx']
    },

    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'babel-loader',
            },
        ]
    }
};
複製代碼

那麼,若是改爲這樣了,TypeScript的類型檢測怎麼辦呢?不是至關於廢了嗎? 你可使用 TypeScript-Babel-Starterfork-ts-checker-webpack-plugin來啓用TypeScript類型檢測。

咱們這裏來講明一下如何使用fork-ts-checker-webpack-plugin

#配置TypeScript類型檢查器

Install

npm install fork-ts-checker-webpack-plugin fork-ts-checker-notifier-webpack-plugin
複製代碼

webpack.config.js

const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');

module.exports = {
    // ...
    plugins: [
        new ForkTsCheckerWebpackPlugin({
            // 將async設爲false,能夠阻止Webpack的emit以等待類型檢查器/linter,並向Webpack的編譯添加錯誤。
            async: false
        }),
        // 將TypeScript類型檢查錯誤以彈框提示
        // 若是fork-ts-checker-webpack-plugin的async爲false時能夠不用
        // 不然建議使用,以方便發現錯誤
        new ForkTsCheckerNotifierWebpackPlugin({
            title: 'TypeScript',
            excludeWarnings: true,
            skipSuccessful: true,
        }),
    ]
};
複製代碼
相關文章
相關標籤/搜索