即时进行编译器的类型检查

时间:2018-07-03 13:04:38

标签: typescript ts-node

我已经根据在文档中找到的内容编写了一个按需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');

0 个答案:

没有答案