Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript compiler API get type of imported names

Consider the following import declaration.

import { a } from "moduleName"

How can I get the declared type of a. For example, ClassDeclaration or FunctionDeclration or Namespace and also the name of the type in the case of a class or function?

In the above example, a is ImportSpecifier, however when I try to resolve it using typeChecker.getSymbolAtLocation and typeChecker.getTypeAtLocation I only get an Identifier of type any.

like image 699
Wickoo Avatar asked May 25 '18 10:05

Wickoo


1 Answers

You can use getTypeAtLocation to get the type of type of the import, and then use type.getSymbol().getDeclarations() to get the symbol and the declarations.

Given the following files:

// module.ts
export class A {
}

export function F(){    
}

// sample.ts
import { A, F} from './module';

This code will output the declarations and the full type name for the imports:

import * as ts from "typescript";

function compile(fileNames: string[], options: ts.CompilerOptions): void {
    let program = ts.createProgram(fileNames, options);
    let sample = program.getSourceFile("sample.ts");
    let checker = program.getTypeChecker();

    let list = sample.getChildAt(0) as ts.SyntaxList;
    let importStm = list.getChildAt(0);
    if (ts.isImportDeclaration(importStm)) { // get the declaration 
        let clauses = importStm.importClause;
        let namedImport = clauses.getChildAt(0); // get the named imports
        if (!ts.isNamedImports(namedImport)) return;
        for (let i = 0, n = namedImport.elements.length; i < n; i++) { // Iterate the named imports
            let imp = namedImport.elements[i];
            console.log(`Import: ${imp.getText()}`);
            // Get Type 
            let type = checker.getTypeAtLocation(imp);
            // Full name 
            console.log(`Name: ${checker.getFullyQualifiedName(type.getSymbol())}`);
            // Get the declarations (can be multiple), and print them 
            console.log(`Declarations: `)
            type.getSymbol().getDeclarations().forEach(d => console.log(d.getText()));
        }

    }
}

compile(["module.ts", "sample.ts"], {}); 

For interfaces there is a complication, the type returned is unknown, this is done intentionally as this comment in the compiler tells us, and it also suggests a work around:

// It only makes sense to get the type of a value symbol. If the result of resolving
// the alias is not a value, then it has no type. To get the type associated with a
// type symbol, call getDeclaredTypeOfSymbol.

So for interfaces we need to use:

let symbol = checker.getSymbolAtLocation(imp.name)
// Get Type 
let type = checker.getDeclaredTypeOfSymbol(symbol);
like image 199
Titian Cernicova-Dragomir Avatar answered Nov 12 '22 03:11

Titian Cernicova-Dragomir