in repo-scripts/prune-dts/prune-dts.ts [368:448]
function extractExportedSymbol(
typeChecker: ts.TypeChecker,
sourceFile: ts.SourceFile,
typeName: ts.Node
): ts.Symbol | undefined {
if (!ts.isIdentifier(typeName)) {
return undefined;
}
if (isExported(typeChecker, sourceFile, typeName)) {
// Don't replace the type reference if the type is already part of the
// public API.
return undefined;
}
const localSymbolName = typeName.escapedText;
const allExportedSymbols = typeChecker.getExportsOfModule(
typeChecker.getSymbolAtLocation(sourceFile)!
);
// Examine all exported types and check if they extend or implement the
// provided local type. If so, we can use the exported type in lieu of the
// private type.
// Short circuit if the local types is already part of the public types.
for (const symbol of allExportedSymbols) {
if (symbol.name === localSymbolName) {
return symbol;
}
}
// See if there is an exported symbol that extends this private symbol.
// In this case, we can safely use the public symbol instead.
for (const symbol of allExportedSymbols) {
for (const declaration of symbol.declarations) {
if (
ts.isClassDeclaration(declaration) ||
ts.isInterfaceDeclaration(declaration)
) {
for (const heritageClause of declaration.heritageClauses || []) {
for (const type of heritageClause.types || []) {
if (ts.isIdentifier(type.expression)) {
const subclassName = type.expression.escapedText;
if (subclassName === localSymbolName) {
// TODO: We may need to change this to return a Union type if
// more than one public type corresponds to the private type.
return symbol;
}
}
}
}
}
}
}
// If no symbol was found that extends the private symbol, check the reverse.
// We might find an exported symbol in the inheritance chain of the local
// symbol. Note that this is not always safe as we might replace the local
// symbol with a less restrictive type.
const localSymbol = typeChecker.getSymbolAtLocation(typeName);
if (localSymbol) {
for (const declaration of localSymbol!.declarations) {
if (
ts.isClassDeclaration(declaration) ||
ts.isInterfaceDeclaration(declaration)
) {
for (const heritageClause of declaration.heritageClauses || []) {
for (const type of heritageClause.types || []) {
if (ts.isIdentifier(type.expression)) {
if (isExported(typeChecker, sourceFile, type.expression)) {
return typeChecker.getSymbolAtLocation(type.expression);
}
}
}
}
}
}
}
return undefined;
}