如何解决在进行类型检查之前转换打字稿
让我们输入打字稿文件:
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在webpack中构建它:
{
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,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;
}
/***/ "/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
转换器有什么区别(我都尝试过但没有发现区别)?以及如何在检查代码之前应用转换?
解决方法
从总体上讲,TypeScript编译器旨在按以下顺序执行以下步骤:
Parse -> Bind -> Type Check -> Emit (transform)
由于这种设计,类型检查器代码通常假定在解析中创建的AST与源文件文本匹配并且没有更改。
例如:
// `declaration` is a variable declaration with type `number`
console.log(typeChecker.typeToString(
typeChecker.getTypeAtLocation(declaration) // number
));
declaration = factory.updateVariableDeclaration(
declaration,declaration.name,/* exclamation token */ undefined,/* type */ factory.createTypeReferenceNode("Date",undefined),/* initializer */ undefined,);
// now type checking won't be reliable
console.log(typeChecker.typeToString(
typeChecker.getTypeAtLocation(declaration) // still number
));
console.log(typeChecker.typeToString(
typeChecker.getTypeAtLocation(declaration.type!) // any
));
因此,您不能可靠地仅转换AST,然后使用现有的TypeScript Compiler API代码进行类型检查。这就是ts-morph实际上对文本(而不是AST)进行修改然后重建AST的原因之一。为了正确执行此操作,需要更新源文件文本和许多内部属性。也就是说,在某些情况下您可能可以摆脱它...
我不确定TS团队在类型检查之前需要花费多少精力来更新编译器以处理转换,而且我不确定他们会投入多少精力,但是您可能想谈一谈向他们询问。在很多情况下,请参见checker.ts中所有导致getTextOfNodeFromSourceText
的呼叫。
before
中after
和getCustomTransformers
之间的差异
正如您所注意到的,这两个变换都是在发射时而不是之前使用的。
-
before
-在编译器进行转换之前要评估的转换-AST中仍将包含TypeScript代码。 -
after
-编译器进行转换后要评估的转换-它将转换为任何“目标”(例如,打印AST将提供JavaScript代码)。
有关更多详细信息,请参见the type declarations。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。