我已经根据在文档中找到的内容编写了一个按需TypeScript编译器类,但是现在我一直无法进行类型检查以处理导入的属性。我想使用此类即时编译节点模块分辨率内的内容,以实现某些我目前无法通过ts-node实现的特定行为。到目前为止,它仍然有效,只有导入的类型检查会带来问题。
有什么想法吗?
基本上.addFileAndEmit()
以filePath作为参数,并将内存中的文件转换为JavaScript,然后,当我们需要在运行时使用带有nodejs的文件时,我(显然这不是下面的代码)将其插入并注入。
由于任何已编译的require语句都位于节点的模块分辨率之内,因此我可以要求transpiler类也对该文件进行编译,然后我们就可以了。我们可以像正常的javascript一样简单地运行ts文件,只是类型检查仅在该转译文件中起作用,但是要说我使用的是我导入的类型,TypeScript无法获得任何有关该类型的信息。这说得通。有什么办法可以实现吗? IDE和ts-node也这样做吗?
import * as fs from "fs";
import * as ts from "typescript";
class TypeScriptCompiler {
filesArray: string[] = [];
files: ts.MapLike<{ version: number }> = {};
options: ts.CompilerOptions = {
module: ts.ModuleKind.CommonJS,
inlineSourceMap: true
};
services: ts.LanguageService;
addFileAndEmit(fileName) {
this.filesArray.push('1.ts')
this.files[fileName] = { version: 0 };
this.emitFile(fileName);
}
servicesHost: ts.LanguageServiceHost = {
getScriptFileNames: () => this.filesArray,
getScriptVersion: fileName =>
this.files[fileName] && this.files[fileName].version.toString(),
getScriptSnapshot: fileName => {
if (!fs.existsSync(fileName)) {
return undefined;
}
return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
},
getCurrentDirectory: () => process.cwd(),
getCompilationSettings: () => this.options,
getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
fileExists: ts.sys.fileExists,
readFile: ts.sys.readFile,
readDirectory: ts.sys.readDirectory
};
constructor() {
this.services = ts.createLanguageService(
this.servicesHost,
ts.createDocumentRegistry()
);
}
emitFile(fileName: string) {
this.services.getProgram();
let output = this.services.getEmitOutput(fileName);
if (!output.emitSkipped) {
console.log(`Emitting ${fileName}`);
} else {
console.log(`Emitting ${fileName} failed`);
this.logErrors(fileName);
}
output.outputFiles.forEach(o => {
console.log(`compiled ${o.name}:`);
console.log(o.text);
// fs.writeFileSync(o.name, o.text, "utf8");
});
}
logErrors(fileName: string) {
let allDiagnostics = this.services
.getCompilerOptionsDiagnostics()
.concat(this.services.getSyntacticDiagnostics(fileName))
.concat(this.services.getSemanticDiagnostics(fileName));
allDiagnostics.forEach(diagnostic => {
let message = ts.flattenDiagnosticMessageText(
diagnostic.messageText,
"\n"
);
if (diagnostic.file) {
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
diagnostic.start!
);
console.log(
` Error ${diagnostic.file.fileName} (${line + 1},${character +
1}): ${message}`
);
} else {
console.log(` Error: ${message}`);
}
});
}
}
const compiler = new TypeScriptCompiler();
compiler.addFileAndEmit('1.ts');
compiler.addFileAndEmit('2.ts');