【问题标题】:TypeScript Compiler API: How to get parent class name?TypeScript Compiler API:如何获取父类名称?
【发布时间】:2021-01-10 01:16:01
【问题描述】:

我正在尝试解析一些打字稿文件以生成一些特定的文档,为此我需要找到属于特定类的所有子类。

我尝试使用这里提出的代码:https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#using-the-type-checker

但它没有指定父类名(或类型)

/**
 * Documentation for C
 */
export class C {
    /**
     * constructor documentation
     * @param a my parameter documentation
     * @param b another parameter documentation
     */
    constructor(a: string, b: C) { }
}

export class D extends C{

}

输出:

[
    {
        "name": "C",
        "documentation": "Documentation for C",
        "type": "typeof C",
        "constructors": [
            {
                "parameters": [
                    {
                        "name": "a",
                        "documentation": "my parameter documentation",
                        "type": "string"
                    },
                    {
                        "name": "b",
                        "documentation": "another parameter documentation",
                        "type": "C"
                    }
                ],
                "returnType": "C",
                "documentation": "constructor documentation"
            }
        ]
    },
    {
        "name": "D",
        "documentation": "",
        "type": "typeof D",
        "constructors": [
            {
                "parameters": [
                    {
                        "name": "a",
                        "documentation": "my parameter documentation",
                        "type": "string"
                    },
                    {
                        "name": "b",
                        "documentation": "another parameter documentation",
                        "type": "C"
                    }
                ],
                "returnType": "D",
                "documentation": "constructor documentation"
            }
        ]
    }
]

但我想要这样的东西:

[
    /** C declaration **/
    {
        "name": "D",
        "documentation": "",
        "type": "C", // because extends C
        "parent": "C", // Or like this 
        "constructors": [
            {
                "parameters": [
                    {
                        "name": "a",
                        "documentation": "my parameter documentation",
                        "type": "string"
                    },
                    {
                        "name": "b",
                        "documentation": "another parameter documentation",
                        "type": "C"
                    }
                ],
                "returnType": "D",
                "documentation": "constructor documentation"
            }
        ]
    }
]

我试图找到有关解析打字稿的文档。如果有人有任何链接或想法,那将是非常可观的!

【问题讨论】:

    标签: typescript


    【解决方案1】:

    这是一个检索父类的完全限定名称的函数,可以插入该函数以生成“父”值(使用版本 3.9.5 测试):

    function getParentClassFQName(node: ts.ClassDeclaration, checker: ts.TypeChecker): string | undefined {
    
        if (!node.heritageClauses) {
            return;
        }
    
        for (let clause of node.heritageClauses) {
            if (clause.token == ts.SyntaxKind.ExtendsKeyword) {
                if (clause.types.length != 1) {
                    console.warn('error parsing extends expression "'+clause.getText()+'"');
                } else {
                    let symbol = checker.getSymbolAtLocation(clause.types[0].expression);
                    if (!symbol) {
                        console.warn('error retrieving symbol for extends expression "'+clause.getText()+'"');
                    } else {
                        return checker.getFullyQualifiedName(symbol);
                    }
                }
            }
        }
    
    }
    

    其中checker=program.getTypeChecker()和node就是这样一个通过ts.isClassDeclaration(node)检查的节点。

    【讨论】:

      【解决方案2】:

      这里没有一个解决方案是完美的 - 一个没有返回正确的答案,一个过于复杂。

      试试这个:

      classType.getBaseTypes()
      

      它返回一个基本类型的数组。我实际上不明白你怎么可能有多个,所以你可能想检查这种情况并抛出一个错误,这样你就知道它是否发生了:

      const getBaseType = (classType) => {
        const baseTypes = classType.getBaseTypes() ?? []
      
        if (baseTypes.length === 0) {
            throw new Error("No base types.")
        }
      
        if (baseTypes.length > 1) {
            throw new Error("> 1 base types; not sure which one to pick!")
        }
      
        return baseTypes[0];
      }
      

      如果您需要获取类的类型,请尝试类似

      const classType = program.getTypeChecker().getTypeAtLocation(classNode)
      

      【讨论】:

      • extend 一个类或接口时不能有多个结果,但implement 其他类型时可以有多个结果。
      【解决方案3】:

      编译器 API 的 TypeChecker 提供了一个名为 getBaseTypeOfLiteralType 的方法。返回值为Type 对象,其中包含symbol: Symbolsymbol 又包含escapedName

      checker.getBaseTypeOfLiteralType(constructorType).symbol.escapedName
      

      您可以将其插入到您使用过的代码的serializeClass 函数中:

      function serializeClass(symbol: ts.Symbol) {
          ...
          (<any>details).baseType = checker.getBaseTypeOfLiteralType(constructorType).symbol.escapedName;
          return details;
      }
      

      这应该会给你这样的输出:

      {
          name: 'D',
          type: 'typeof D',
          constructors: [ ... ],
          baseType: 'C'
      }
      

      【讨论】:

      • 您好,感谢您的帮助,但返回的 baseType 仍然是“D”。我继续调查……如果有其他想法……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      • 2021-08-14
      • 1970-01-01
      • 2017-12-30
      • 1970-01-01
      • 2020-06-21
      相关资源
      最近更新 更多