将推断的映射类型发送到.d.ts

时间:2019-11-04 18:30:31

标签: typescript typescript-compiler-api

我在文件中有一个名为Commands的映射类型,如下所示:

// File: protocol.ts

import { CArgs, CRes } from '../utils';

type S = import('src/applications').Services;
export type Commands = {
    -readonly [P in keyof S]: {
        args: CArgs<S[P]>;
        res: CRes<S[P]>;
    };
};

// ... more declarations

推论非常复杂,Services本身就是一种映射类型,它是使用UnionToIntersection和更多奇特的事物推论得出的,其类型来自许多不同的文件...但是它可以工作并且由TypeScript推断的类型是这样的:

type Commands = {
    Com1: {
        args: number;
        res: void;
    };
    Com2: {
        args: {foo: string};
        res: string[];
    };
    // ... etc ...
};

现在,我想发出一个具有 resolved类型的单个.d.ts文件,如第二个片段所示,因此客户端不需要整个文件树的声明来推断方式。换句话说,我想“粘贴”从TypeScript推断出的类型,替换Commands声明并删除所有import语句。

我认为我需要使用编译器API,但是我能找到的小型文档不是很清楚。老实说,我什至不知道从哪里开始。

我如何执行该任务?

我首先使用给出文件名Program的{​​{1}}创建了ts.createProgram()。我从那里访问了每个节点,所以我知道文件已加载。我创建了一个protocol.ts,几乎每个TypeChecker都使用了.getTypeAtLocation(),记录了Nodechecker.typeToString(type)等,但是没有推断类型的踪迹。也许类型检查器或程序需要加载每个文件? (我以为它会自己做)如果是这样,如何从checker.GetFullyQualifiedName(type.symbol)中的glob模式创建数组?

如您所见,我有点迷失了,欢迎任何帮助和指导。

非常感谢您。

1 个答案:

答案 0 :(得分:0)

我几乎可以肯定,还有一种更好的方法,但是在编译器API的incremental example之后,我能够获得与VSCode显示的信息相同的信息。

给出./src/mapped-types.ts是:

type A = { a: 1, b: 2, c: 3 }

export type Mapped = {
    readonly [K in keyof A]: A[K]
}

将输出以下代码:

type Mapped = {
    readonly a: 1;
    readonly b: 2;
    readonly c: 3;
}
import * as ts from 'typescript'
import * as fs from 'fs'

const rootFileNames = ['./src/mapped-types.ts']

const files: ts.MapLike<{ version: number }> = {};

const servicesHost: ts.LanguageServiceHost = {
    getScriptFileNames: () => rootFileNames,
    getScriptVersion: fileName => files[fileName] && files[fileName].version.toString(),
    getScriptSnapshot: fileName => {
        if (!fs.existsSync(fileName)) {
            return undefined;
        }

        return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
    },
    getCurrentDirectory: () => process.cwd(),
    getCompilationSettings: () => ({}),
    getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
    fileExists: ts.sys.fileExists,
    readFile: ts.sys.readFile,
    readDirectory: ts.sys.readDirectory
};

// Create the language service files
const services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());

const index = fs.readFileSync(rootFileNames[0], 'utf-8').indexOf('Mapped')
const info = services.getQuickInfoAtPosition(rootFileNames[0], index)!
console.log(ts.displayPartsToString(info.displayParts))

获取快速信息的相关代码是here,不幸的是那里发生了很多我不理解的事情,所以我不确定如何向正确的方向指出。