A typescript transformer that convert exported const enum into object literal.
This is just like the one from @babel/preset-typescript with optimizeConstEnums: true but it works for typescript compiler.
This will transform exported const enum from
export const enum MyEnum {
A,
B,
C,
D = 10,
E = C * 200,
}
into object literal like this
export const MyEnum = {
A: 0,
B: 1,
C: 2,
D: 10,
E: 400,
} as const;
and it also strips const
in declaration file, to make your code compatible with --isolatedModules
// my-enum.d.ts
declare enum MyEnum { A: 0, ... }
Const enum can only works in the same file. It works by inlining the exact value into code.
if (cond === MyEnum.A) { /*...*/ }
will compile to the following code. That's a great inline optimization.
if (cond === 0 /* A */) { /*...*/ }
However, const enums only work in the same file with isolateModules. Therefore, you can't use the exported const enum. The solution is to enable preserveConstEnums option to convert const enums to regular enums.
And the regular enum compiles to
export var MyEnum;
(function(MyEnum) {
MyEnum[MyEnum['A'] = 0] = 'A';
MyEnum[MyEnum['B'] = 1] = 'B';
MyEnum[MyEnum['C'] = 2] = 'C';
MyEnum[MyEnum['D'] = 10] = 'D';
MyEnum[MyEnum['E'] = 400] = 'E';
})(MyEnum || (MyEnum = {}));
which is verbose. Not only can't you take advantage of enum inlining, but it also wastes a lot of bytes. That's the reason why this transform is made.
Although keys of object literals can't be tree-shaken by webpack, however, the exported object literals have no side effects like enums do. If one of your code-splitting chunks does not use it, it will be completely erased.
npm install ts-transformer-optimize-const-enum --save-dev
If you use vanilla TypeScript compiler, you can use this with ttypescript and compile with ttsc
instead of tsc
// tsconfig.json
{
"compilerOptions": {
// ...
"plugins": [
{ "transform": "ts-transformer-optimize-const-enum" },
{ "transform": "ts-transformer-optimize-const-enum", "afterDeclarations": true },
]
},
// ...
}
The afterDeclarations part is to strip out const keyword from declaration file.
// webpack.config.js
const optimizeConstEnum = require('ts-transformer-optimize-const-enum').default;
module.exports = {
// ...
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader', // or 'awesome-typescript-loader'
options: {
getCustomTransformers: program => ({
before: [
optimizeConstEnum(program),
],
afterDeclarations: [
optimizeConstEnum(program),
],
}),
},
},
],
},
};
// rollup.config.js
import typescript from '@rollup/plugin-typescript';
import optimizeConstEnum from 'ts-transformer-optimize-const-enum';
export default {
// ...
plugins: [
typescript({
transformers: [service => ({
before: [
optimizeConstEnum(service.getProgram()),
],
afterDeclarations: [
optimizeConstEnum(service.getProgram()),
],
})],
}),
],
};