9

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.

1 Answer 1

13

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);
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! In the statement let type = checker.getTypeAtLocation(imp);, type will be undefined when importing an interface. Any tips how to get it working for interfaces?
When I do let type = checker.getTypeAtLocation(imp) I get back the following object: { flags: 1, id: 4, intrinsicName: "error", objectFlags: 0 }. I'm using TypeScript v4.9.3. What am I doing wrong?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.