Overall goal is to extract type information from exported modules. However, it seems navigating to the actual definition is required, example:
From my experience, you will need to get the aliased symbol if the symbol is an alias in this case.
function getDefaultExportDeclaration(fileSymbol: ts.Symbol) {
if (fileSymbol.exports == null)
return undefined;
const defaultSymbol = fileSymbol.exports.get(ts.escapeLeadingUnderscores("default"));
return defaultSymbol == null
? undefined
: getAliasedSymbolIfNecessary(defaultSymbol).valueDeclaration;
}
function getAliasedSymbolIfNecessary(symbol: ts.Symbol) {
if ((symbol.flags & ts.SymbolFlags.Alias) !== 0)
return typeChecker.getAliasedSymbol(symbol);
return symbol;
}
For example, with the following code that uses this function:
// setup (this is my library that provides an easier setup with the compiler api)
import { Project, ts } from "@ts-morph/bootstrap";
const project = new Project();
const fileA = project.createSourceFile("fileA.ts", `function Foo() {} export default Foo;`);
const fileB = project.createSourceFile("fileB.ts", `export default function Foo() {}`);
const fileC = project.createSourceFile("fileC.ts", `import Foo from "./FileB";
export default Foo;`);
const program = project.createProgram();
const typeChecker = program.getTypeChecker();
// get result and output
console.log(getDefaultExportDeclaration(typeChecker.getSymbolAtLocation(fileA)!)!.getText());
console.log(getDefaultExportDeclaration(typeChecker.getSymbolAtLocation(fileB)!)!.getText());
console.log(getDefaultExportDeclaration(typeChecker.getSymbolAtLocation(fileC)!)!.getText());
The output will be:
function Foo() {}
export default function Foo() {}
export default function Foo() {}