Typescript CompilerAPI:如何获取“扩展”类型 AST

ole*_*egz 5 typescript typescript-compiler-api

我的应用程序中的类型以一种有些复杂的方式定义:我在函数上定义代数,构造“解码器”函数,然后从解码器推断类型(请参阅 gcanti/io-fp)。有一个问题报告给 typedoc 项目#1519

现在我想编写一个实用程序来为我的 API 生成正确的 .d.ts 文档,以便输出:

export declare type BorderStyleEnum = 'None' | 'Solid';
export declare type BorderStyle = {
    Color?: string;
    Style?: BorderStyleEnum;
    Width?: string;
};
export declare type BorderSideStyle = {
    Color?: string;
    Style?: '' | 'None' | 'Solid';
    Width?: string;
};
export declare type BorderSideStyleEnum = NonNullable<BorderSideStyle['Style']>;
export declare type Style = { Border: BorderStyle; TopBorder: BorderSideStyle; LeftBorder: BorderSideStyle; BottomBorder: BorderSideStyle; RightBorder: BorderSideStyle;
};
export declare type StyleExp = ExpandRecursively<Style>;
declare function item(): {
    /** type of the element */
    type: 'item';
    name: string;
    style: Style;
};
export declare type Expand<T> = T extends infer O ? {
    [K in keyof O]: O[K];
} : never;
export declare type ExpandRecursively<T> = T extends object ? T extends infer O ? {
    [K in keyof O]: ExpandRecursively<O[K]>;
} : never : T;
export declare type Item = ExpandRecursively<ReturnType<typeof item>>;
export {};
Run Code Online (Sandbox Code Playgroud)

像这样变得更紧凑(我手动制作的)

export type BorderStyleEnum = "None" | "Solid";
export type BorderStyle = { Color?: string; Style?: BorderStyleEnum; Width?: string; };
export type BorderSideStyle = { Color?: string; Style?: BorderSideStyleEnum; Width?: string; };
export type BorderSideStyleEnum = "" | "None" | "Solid";
export type Style = { Border: BorderStyle; TopBorder: BorderSideStyle; LeftBorder: BorderSideStyle; BottomBorder: BorderSideStyle; RightBorder: BorderSideStyle; };
export type StyleExp = Style;
export type Item = { type: "item"; name: string; style: Style };
Run Code Online (Sandbox Code Playgroud)

目前我正在使用以下代码片段来获取类型定义:


    const type = typeChecker.getTypeAtLocation(node);
    const typeDecl = typeChecker.typeToString(type, node,
        ts.TypeFormatFlags.NoTruncation
        // | ts.TypeFormatFlags.MultilineObjectLiterals
        | ts.TypeFormatFlags.InTypeAlias
        // | ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope  // prevents type expansion
        // | ts.TypeFormatFlags.UseStructuralFallback
        );
Run Code Online (Sandbox Code Playgroud)

它确实工作得很好并且“扩展”了复杂的类型,例如:export type Item = ExpandRecursively<ReturnType<typeof item>>;

然而,我的目标是获得扩展定义的 AST,以便我可以应用我自己的“简化”规则。

示例代码位于https://replit.com/@OlegZaimkin/KhakiBrokenPagerecognition#index.ts

有没有办法将类型评估/解析到尽可能低的级别并获得结果的 AST?还有其他想法可以解决原来的问题吗?

答案:看起来NodeBuilderFlags.InTypeAlias成功了。typeToTypeNode我通过将此标志添加到 的参数中,成功获得了“扩展”类型的 AST flags

var rnode = typeChecker.typeToTypeNode(type, undefined,
        ts.NodeBuilderFlags.NoTruncation
        | ts.NodeBuilderFlags.InTypeAlias
        );
Run Code Online (Sandbox Code Playgroud)