Input Code
function observable() {}
class Example {
@observable()
toolbar = 'example';
}
export default Example;
JavaScript output
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 output
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;
我们发现两者编译出的装饰器属性代码并不相同。
现在我们创建一个javascript类ExampleEnhance
,继承typescript类Example
,并重写装饰器属性toolbar
。
// This is javascript code, but class Example is typescript
class ExampleEnhance extends Example {
@observable()
toolbar = 'YY';
}
这时,我们期望toolbar
的值为'YY'
,但是我们发现它的值仍然是'example'
。
怎么办?
我们有没有办法让TypeScript
和JavaScript
装饰器属性编译出来的代码相同呢?
我们从TypeScript官方得到的回复是
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.
Because Typescript's decorator specification is not quite the same as anyone else's, they are always transformed.
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.
因此,要让两者编译出相同的代码,我们必须要把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-Starter 或 fork-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,
}),
]
};
网友评论