gpt4 book ai didi

typescript - 如何键入检查内存中的 TypeScript 代码片段?

转载 作者:行者123 更新时间:2023-12-03 13:51:04 26 4
gpt4 key购买 nike

我正在我的应用程序 Data-Forge Notebook 中实现 TypeScript 支持。

我需要编译、类型检查和评估 TypeScript 代码片段。

编译好像没问题,我用的是transpileModule如下所示,将一段 TS 代码转换为可评估的 JavaScript 代码:

import { transpileModule, TranspileOptions } from "typescript";

const transpileOptions: TranspileOptions = {
compilerOptions: {},
reportDiagnostics: true,
};

const tsCodeSnippet = " /* TS code goes here */ ";
const jsOutput = transpileModule(tsCodeSnippet, transpileOptions);
console.log(JSON.stringify(jsOutput, null, 4));

但是,当我尝试编译有错误的 TS 代码时出现问题。

例如,下面的函数有一个类型错误,但它在没有任何错误诊断的情况下被转换:
function foo(): string {
return 5;
}

转译很棒,但我也希望能够向我的用户显示错误。

所以我的问题 是如何做到这一点,而且还要进行类型检查并为语义错误产生错误?

请注意,我不想将 TypeScript 代码保存到文件中。这对我的应用程序来说将是一个不必要的性能负担。我只想编译和键入保存在内存中的代码片段。

最佳答案

情况 1 - 仅使用内存 - 无法访问文件系统(例如在网络上)
这不是一项简单的任务,可能需要一段时间才能完成。也许有更简单的方法,但我还没有找到。

  • 实现 ts.CompilerHost ,其中 fileExistsreadFiledirectoryExistsgetDirectories() 等方法从内存而不是实际文件系统中读取。
  • 根据需要(例如 lib.es6.d.ts 或 lib.dom.d.ts)将适当的 lib 文件加载到内存文件系统中。
  • 将您的内存文件也添加到内存文件系统中。
  • 创建一个程序(使用 ts.createProgram )并传入您的自定义 ts.CompilerHost
  • 调用 ts.getPreEmitDiagnostics(program) 获取诊断信息。

  • 不完美的例子
    这是一个简短的不完美示例,它没有正确实现内存文件系统并且没有加载 lib 文件(因此会有全局诊断错误......这些可以被忽略,或者您可以在 program 上调用特定方法而不是 program.getGlobalDiagnostics() 。注意 ts.getPreEmitDiagnostics here ) 的行为:
    import * as ts from "typescript";

    console.log(getDiagnosticsForText("const t: number = '';").map(d => d.messageText));

    function getDiagnosticsForText(text: string) {
    const dummyFilePath = "/file.ts";
    const textAst = ts.createSourceFile(dummyFilePath, text, ts.ScriptTarget.Latest);
    const options: ts.CompilerOptions = {};
    const host: ts.CompilerHost = {
    fileExists: filePath => filePath === dummyFilePath,
    directoryExists: dirPath => dirPath === "/",
    getCurrentDirectory: () => "/",
    getDirectories: () => [],
    getCanonicalFileName: fileName => fileName,
    getNewLine: () => "\n",
    getDefaultLibFileName: () => "",
    getSourceFile: filePath => filePath === dummyFilePath ? textAst : undefined,
    readFile: filePath => filePath === dummyFilePath ? text : undefined,
    useCaseSensitiveFileNames: () => true,
    writeFile: () => {}
    };
    const program = ts.createProgram({
    options,
    rootNames: [dummyFilePath],
    host
    });

    return ts.getPreEmitDiagnostics(program);
    }
    情况 2 - 访问文件系统
    如果您可以访问文件系统,那么这会容易得多,您可以使用类似于以下的功能:
    import * as path from "path";

    function getDiagnosticsForText(
    rootDir: string,
    text: string,
    options?: ts.CompilerOptions,
    cancellationToken?: ts.CancellationToken
    ) {
    options = options || ts.getDefaultCompilerOptions();
    const inMemoryFilePath = path.resolve(path.join(rootDir, "__dummy-file.ts"));
    const textAst = ts.createSourceFile(inMemoryFilePath, text, options.target || ts.ScriptTarget.Latest);
    const host = ts.createCompilerHost(options, true);

    overrideIfInMemoryFile("getSourceFile", textAst);
    overrideIfInMemoryFile("readFile", text);
    overrideIfInMemoryFile("fileExists", true);

    const program = ts.createProgram({
    options,
    rootNames: [inMemoryFilePath],
    host
    });

    return ts.getPreEmitDiagnostics(program, textAst, cancellationToken);

    function overrideIfInMemoryFile(methodName: keyof ts.CompilerHost, inMemoryValue: any) {
    const originalMethod = host[methodName] as Function;
    host[methodName] = (...args: unknown[]) => {
    // resolve the path because typescript will normalize it
    // to forward slashes on windows
    const filePath = path.resolve(args[0] as string);
    if (filePath === inMemoryFilePath)
    return inMemoryValue;
    return originalMethod.apply(host, args);
    };
    }
    }

    // example...
    console.log(getDiagnosticsForText(
    __dirname,
    "import * as ts from 'typescript';\n const t: string = ts.createProgram;"
    ));
    这样做,编译器将在提供的 rootDir 中搜索 node_modules 文件夹并使用其中的类型(它们不需要以其他方式加载到内存中)。
    更新:最简单的解决方案
    我创建了一个名为 @ts-morph/bootstrap 的库,它使得使用 Compiler API 进行设置变得更加容易。即使使用内存文件系统,它也会为您加载 TypeScript lib 文件。
    import { createProject, ts } from "@ts-morph/bootstrap";

    const project = await createProject({ useInMemoryFileSystem: true });

    const myClassFile = project.createSourceFile(
    "MyClass.ts",
    "export class MyClass { prop: string; }",
    );

    const program = project.createProgram();
    ts.getPreEmitDiagnostics(program); // check these

    关于typescript - 如何键入检查内存中的 TypeScript 代码片段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53733138/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com