Возьмем машинописный файл:
class A {
private x? = 0;
private y? = 0;
f() {
console.log(this.x, this.y);
delete this.x;
}
}
const a = new A();
a.f();
Я создаю его в веб-пакете, используя awesome-typescript-loader:
{
test: /\.tsx?$/,
include: path.resolve("./src"),
exclude: path.resolve("./node_modules/"),
use: {
loader: 'awesome-typescript-loader',
options: {
getCustomTransformers: program => ({
before: [deleteTransformer(program)]
})
}
}
},
Где deleteTransformer
- мой собственный преобразователь, который заменяет любое выражение delete
на delete this.y
:
import * as ts from "typescript";
export default function getCustomTransformers(program: ts.Program): ts.TransformerFactory<ts.SourceFile> {
return (context: ts.TransformationContext) => (file: ts.SourceFile) => visitNodeAndChildren(file, program, context);
}
function visitNodeAndChildren<N extends ts.Node>(node: N, program: ts.Program, context: ts.TransformationContext): N {
return ts.visitEachChild(visitNode(node, program), childNode => visitNodeAndChildren(childNode, program, context), context);
}
function visitNode<N extends ts.Node>(node: N, program: ts.Program): N {
if (ts.isDeleteExpression(node)) {
return ts.factory.createDeleteExpression(ts.factory.createPropertyAccessExpression(
ts.factory.createThis(),
"y",
)) as ts.Node as N;
}
return node;
}
Если я запущу компиляцию, я получу ожидаемый код (удаляет y
, а не x
):
/***/ "/7QA":
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var A = /** @class */ (function () {
function A() {
this.x = 0;
this.y = 0;
}
A.prototype.f = function () {
console.log(this.x, this.y);
delete this.y;
};
return A;
}());
var a = new A();
a.f();
/***/ }),
Но если я изменю имя y
на z
, которого нет в классе A
, я не получу сообщения об ошибке.
Также, если я изменю класс A
на необязательный x
и оставлю y
в трансформаторе, я получу сообщение об ошибке
× 「atl」: Checking finished with 1 errors
ERROR in [at-loader] ./src/index.ts:7:16
TS2790: The operand of a 'delete' operator must be optional.
В соответствии с этими фактами я понимаю, что преобразователь применяется после фактической проверки кода, но преобразователь включен в раздел before
, поэтому я ожидаю, что машинописный текст будет проверять сгенерированный код вместо оригинала.
Почему это происходит? В чем разница между трансформаторами before
и after
в объекте getCustomTransformers
(я пробовал оба и не нашел никакой разницы)? И как я могу применить преобразования до того, как код будет проверен?