typescript-api-extractor
v1.0.0-beta.6
Published
Extracts API description from TypeScript code
Downloads
61,568
Readme
TypeScript API Extractor
A utility for extracting API descriptions from TypeScript definitions using the TypeScript Compiler API. This tool analyzes TypeScript source code and generates structured metadata about exported functions, components, interfaces, types, and more.
Features
- 🔍 Extract API information from TypeScript source files
- ⚛️ React component analysis with prop types and documentation
- 🏷️ Type definitions including interfaces, enums, and type aliases
- 📝 JSDoc comments parsing and extraction
- 🔗 Reference resolution for complex type relationships
- 🎯 Selective parsing of specific files or entire projects
Installation
npm install typescript-api-extractoror with yarn:
yarn add typescript-api-extractoror with pnpm:
pnpm add typescript-api-extractorUsage
import {
createProgram,
loadConfig,
parseFromProgram,
type ModuleNode,
} from 'typescript-api-extractor';
// Load TypeScript configuration
const config = loadConfig('./tsconfig.json');
const program = createProgram(config.fileNames, config.options);
// Parse all files in the project
for (const file of config.fileNames) {
try {
const moduleInfo: ModuleNode = parseFromProgram(file, program);
console.log(`Extracted API from ${file}:`, moduleInfo);
} catch (error) {
console.error(`Failed to parse ${file}:`, error);
}
}API Reference
createProgram
Re-export of TypeScript’s createProgram from the TypeScript version bundled with typescript-api-extractor. It has the same overloads/signature as typescript.createProgram and returns a Program.
loadConfig(tsConfigPath: string)
Loads and parses a TypeScript configuration file.
- Parameters:
tsConfigPath: Path to thetsconfig.jsonfile
- Returns:
{ options: CompilerOptions, fileNames: string[] }
parseFile(filePath: string, options: CompilerOptions, parserOptions?: ParserOptions)
Parses a single TypeScript file and returns the extracted API information.
- Parameters:
filePath: Path to the TypeScript file to parseoptions: TypeScript compiler optionsparserOptions: Optional parser configuration
- Returns:
ResolvedModuleNodeby default, orSyntaxOnlyModuleNodewhenparserOptions.typeOperatorOutputis the literal'syntaxOnly'. A dynamicParserOptionsvalue returns their union.
parseFromProgram(filePath: string, program: Program, parserOptions?: ParserOptions)
Parses a file from an existing TypeScript program for better performance when parsing multiple files.
- Parameters:
filePath: Path to the file to parseprogram: TypeScript program instanceparserOptions: Optional parser configuration
- Returns:
ResolvedModuleNodeby default, orSyntaxOnlyModuleNodewhenparserOptions.typeOperatorOutputis the literal'syntaxOnly'. A dynamicParserOptionsvalue returns their union.
Configuration Options
The parser accepts optional configuration through the ParserOptions interface:
interface ParserOptions {
shouldInclude?: (data: { name: string; depth: number }) => boolean | undefined;
shouldResolveObject?: (data: {
name: string;
propertyCount: number;
depth: number;
propertyDepth: number;
}) => boolean | undefined;
includeExternalTypes?: boolean;
typeOperatorOutput?: 'resolved' | 'syntaxOnly';
onWarning?: (warning: ParserWarning) => void;
}
type ParserWarning =
| UnsupportedTypeFallbackWarning
| MissingEnumDeclarationWarning
| MissingDefaultExportSymbolWarning;
interface ParserWarningBase {
message: string;
filePath: string;
line: number;
column: number;
parsedSymbolStack: string[];
}
interface UnsupportedTypeFallbackWarning extends ParserWarningBase {
code: 'unsupported-type-fallback';
typeFlags: string[];
typeText: string;
sourceText?: string;
}
interface MissingEnumDeclarationWarning extends ParserWarningBase {
code: 'missing-enum-declaration';
enumName: string;
}
interface MissingDefaultExportSymbolWarning extends ParserWarningBase {
code: 'missing-default-export-symbol';
sourceText: string;
}shouldResolveObject decides whether an object's shape is expanded or reduced to
a bare object. Returning undefined falls back to
(propertyDepth === 0 || propertyCount <= 50) && depth <= 10.
depth counts every type on the resolution stack, while propertyDepth counts
only the property (and index signature) values traversed to reach the object. A
propertyDepth of 0 means the object is the export's own type or something
reached from it through composition alone - aliases, unions, intersections, and
the parameter and return types of its call signatures. The default rule applies
the property-count limit only above that, so a large component prop list is
reported in full while its individual props stay bounded.
When onWarning is omitted, recoverable parser warnings are printed with
console.warn. Provide onWarning to collect or format them yourself.
Output Format
The parser returns a module object with the following structure. The default
ResolvedModuleNode and opt-in SyntaxOnlyModuleNode types are recursively
mode-aware versions of ModuleNode; both remain structurally compatible with
the runtime model.
interface ModuleNode {
name: string;
exports: ExportNode[];
}
interface ExportNode {
name: string;
type: TypeNode;
documentation?: DocumentationNode;
}TypeNode represents a TypeScript type. There are multiple classes of types. See the contents of the src/models/types directory to discover them.
Type Operators
Authored keyof expressions are represented without expanding away their syntax:
interface TypeOperatorNode {
kind: 'typeOperator';
operator: 'keyof';
type: TypeNode;
resolvedType?: TypeNode;
resolutionKind?: 'exact' | 'baseConstraint' | 'fallback';
}
type ResolvedTypeOperatorNode = Omit<TypeOperatorNode, 'resolvedType' | 'resolutionKind'> & {
resolvedType: TypeNode;
resolutionKind: 'exact' | 'baseConstraint' | 'fallback';
};
type SyntaxOnlyTypeOperatorNode = Omit<TypeOperatorNode, 'resolvedType' | 'resolutionKind'> & {
resolvedType?: never;
resolutionKind?: never;
};The exported TypeOperatorNode class represents both runtime modes, so its
payload fields are optional. Parser entry points correlate them recursively:
default and literal 'resolved' calls return ResolvedModuleNode, literal
'syntaxOnly' calls return SyntaxOnlyModuleNode, and a dynamic mode returns
their union.
Type-query operands retain their authored expression without expanding the queried value shape:
interface TypeQueryNode {
kind: 'typeQuery';
expressionName: string;
}For example, the type of keyof typeof value is a TypeQueryNode whose
expressionName is value.
Readonly arrays and tuples expose isReadonly: true in their public output,
including when they are nested inside a preserved operator:
interface ArrayNode {
kind: 'array';
typeName?: TypeName;
elementType: TypeNode;
isReadonly?: true;
}
interface TupleNode {
kind: 'tuple';
typeName?: TypeName;
types: TypeNode[];
isReadonly?: true;
}The optional field is omitted for mutable containers and serialized as true
for readonly containers. This keeps rendered operands and their resolved key
sets consistent.
typeis the authored operand. Named object operands are intentionally shallow references because expanding their properties does not change the operator or its key result.resolvedTypeis the checker result used to describe the keys available from the operator. SettypeOperatorOutput: 'syntaxOnly'to omit this potentially large payload together withresolutionKind; the default is'resolved'.resolutionKind: 'exact'meansresolvedTypeis the concrete result.resolutionKind: 'baseConstraint'means the operand is still generic, soresolvedTypeis the best available base constraint rather than its eventual instantiated result. For example,keyof Tcommonly resolves tostring | number | symbolat extraction time.resolutionKind: 'fallback'means the checker exposed neither a usable constraint nor a result the model can represent exactly; unsupported concrete results are represented byanyand emit anunsupported-type-fallbackwarning.
Preservation follows authored operators through the supported reference,
container, mapped, indexed-access, conditional-branch, and heritage paths. It
does not reconstruct operators after TypeScript selector or inference utilities
have erased their source syntax. For example, ReturnType, Parameters,
Awaited, ConstructorParameters, ThisParameterType, and user-authored
conditional infer selectors can expose only their reduced semantic result.
Example Output
For a React component like this:
interface Props {
/** The title to display */
title: string;
/** Whether the component is disabled */
disabled?: boolean;
}
export function MyComponent(props: Props) {
return <div>{props.title}</div>;
}ModuleNode.name is the parsed file path relative to compilerOptions.rootDir,
including the file extension. For a file at src/MyComponent.ts, the extractor
would produce:
{
"name": "src/MyComponent.ts",
"exports": [
{
"name": "MyComponent",
"type": {
"kind": "component",
"typeName": {
"name": "MyComponent"
},
"props": [
{
"name": "title",
"type": {
"kind": "intrinsic",
"intrinsic": "string"
},
"optional": false,
"documentation": {
"description": "The title to display"
}
},
{
"name": "disabled",
"type": {
"kind": "intrinsic",
"intrinsic": "boolean"
},
"optional": true,
"documentation": {
"description": "Whether the component is disabled"
}
}
]
}
}
]
}Technical Notes
The parser code is split into a few layers. Type-class modules live in the resolver pipeline: each one chooses whether a TypeScript type shape applies and constructs the corresponding output model node. Shared helpers exist only for substructures that are reused across multiple type classes.
Architecture Principles
- Keep normalization and construction as separate phases. Export parsing first
creates
ExportDescriptorrecords, then converts them intoExportNodemodels once export targeting, namespace metadata, and re-export metadata are stable. - Keep type resolution as an ordered pipeline. Resolver order is observable for overlapping TypeScript shapes, so broad fallback resolvers should stay behind more specific resolvers.
- Keep parser context scoped. Parser code should use the internal
ScopedParserContextscope helpers for symbol stacks, source-node stacks, and type-parameter substitutions instead of mutating ambient parser state directly. The publicParserContextstays the observable parser state and options shape. - Keep model policy centralized. Type model classes are DTO-like and can render themselves, while compound normalization and structural equivalence live in dedicated model helpers.
Entry Points
src/parsers/moduleParser.tsandsrc/parsers/exportParser.tswalk source files and exported declarations.src/parsers/exportDescriptors.tsnormalizes export symbols intoExportDescriptorrecords before any output model nodes are built. It owns export-specifier targeting, namespace merging, re-export metadata, export type acquisition, and recoverable export warnings.src/parsers/exportTransforms.tsapplies post-export transforms after generic export nodes are built. Today it runs the React component transform fromcomponentParser.ts.src/parsers/componentParser.tscontains React component-specific extraction and should remain a transform policy rather than a generic export parser. It recognizes both a single function type and a union of them, so a polymorphic component whose arms differ per prop form still reports one merged prop list. Return types are matched by name rather than by resolved node kind, soincludeExternalTypeschanges how much detail the output carries without changing what counts as a component.src/parsers/typeResolver.tsis the public type-resolution facade used by the rest of the parser. It should stay small; the resolver implementation lives in the session and resolver modules.src/parserContextFactory.tsconstructs the scoped parser context shared by production entry points and focused parser tests, including balanced diagnostic and substitution scopes.
Type Resolution
src/parsers/typeResolutionSession.tsowns cross-cutting resolution mechanics: caching, recursion guards, type-parameter substitutions, warning replay, and the active resolver callback used by nested type-class handlers and helpers.src/parsers/typeResolutionTypes.tsdefines the contracts shared by the resolver pipeline. Resolvers receive aTypeResolutionRequestand aTypeResolutionSession.ScopedParserContext(insrc/parserContext.ts) exposes scoped parser-context helpers for diagnostic symbol scopes, diagnostic source-node scopes, and temporary type-parameter substitutions. Parser code should use these helpers instead of manually pushing and popping diagnostic stacks or swapping substitution maps. The publicParserContext(exported fromsrc/parser.ts) stays focused on observable parser state and options.src/parsers/typeResolutionDiagnostics.tscentralizes recoverable fallback warnings, including source-location selection and TypeScript flag formatting.src/parsers/typeResolutionUtils.tsisolates TypeScript internal API access, such as private type IDs and shallow cycle placeholders.src/parsers/authoredTypeReferenceBindings.tsderives shared authored and semantic generic bindings across references and interface/class heritage so member, signature, and container resolution use the same specialization.src/parsers/typeParameterBindings.tspairs semantic arguments and authored argument nodes with every checker symbol that can represent a generic parameter during nested resolution.src/parsers/typeContainerUtils.tscentralizes compiler-backed array and tuple identity, readonly-state, and tuple-element syntax helpers shared by container resolvers.src/parsers/sourceFileUtils.tsowns the deliberately distinct broad and path-segment-basednode_modulespolicies used by semantic and authored-syntax traversal.
Type-Class Resolvers
All resolver pipeline modules live in src/parsers/typeResolvers/.
index.tsis the ordered resolver registry. Resolver order is meaningful: syntax-first operators and specific shapes should appear before semantic fallbacks that would discard authored syntax.authoredTypeAlias.tsreplays alias bodies whose supported syntax containskeyof, carries generic substitutions across local and relative-import alias chains, and preserves source-only preflight checks where export normalization must not perturb TypeScript's lazy caches.referencedTypeAlias.tscentralizes type-alias lookup for ordinary references andimport()type references used by container and operator helpers.arrayTypeResolver.tshandles arrays and element-type recursion.classTypeResolver.tshandles class detection, constructor model assembly, constructor documentation, class members, static members, and class type parameters.enumTypeResolver.tshandles enum-like flags and enum symbol/member extraction.functionTypeResolver.tshandles callable type selection and function model assembly.intrinsicTypeResolver.tshandles all primitive/intrinsic flags such asstring,number,boolean,void,any,unknown,null, andnever.intersectionTypeResolver.tshandles intersection members and any merged callable/object shape TypeScript exposes for the intersection.literalTypeResolver.tshandles string/number/bigint/boolean literal nodes.objectTypeResolver.tshandles object-like types, object properties, index signatures, mapped-type index signatures, and object-keyword fallback.tupleTypeResolver.tshandles tuple element resolution and tuple arity.typeOperatorTypeResolver.tspreserves authoredkeyofsyntax, resolves its operand and semantic result separately, and records whether that result is exact, a base constraint, or a fallback.typeOperatorTypeNodes.tscontains the shared syntax helpers used to find and propagate authoredkeyofnodes through parenthesized and nested type syntax.unionTypeResolver.tsowns union-specific behavior, including preserving authored union member order and overlapping type-operator members fromTypeNodes.specialTypeResolvers.tshandles TypeScript-internal or context-sensitive shapes such as type parameters, conditional types, indexed access types, and substitution fallbacks.externalTypeResolver.tscontains the external-type policy used whenincludeExternalTypesis disabled.signatureTypeParameterNodes.tsis a shared helper for signature type parameter metadata used by class and function resolvers.signatureParser.tsowns shared function-like signature parsing: call signatures, parameters, parameter docs/defaults, and return types used by callable exports, constructors, and class methods.
A resolver should answer, "Does this ts.Type shape apply, and if so, which
model node should represent it?" It should keep pipeline concerns such as
ordering, fallback choice, and session recursion explicit. If it needs nested
type resolution, it should use the active resolver callback from the current
TypeResolutionSession instead of importing resolveType directly.
Model Construction
- Classes in
src/models/types/are model DTOs with rendering helpers such astoString(). They should not own parser policy. Compound constructors are the only exception: they delegate member normalization totypeCanonicalizerso all callers get the same union/intersection behavior from normal construction. src/models/typeCanonicalizer.tsowns compound member normalization such as flattening nested compounds, simplifying boolean literal unions, removing redundantnever, keeping nullish members at the end, and deduplicating members. It exports the singletontypeCanonicalizer; the implementation class is internal so callers use one shared normalization policy.src/models/typeEquivalence.tsowns structural equivalence checks used by canonicalization, including the intentional rule that unaliasedanycan act as a wildcard when choosing between duplicate generated signatures. It exports the singletontypeEquivalenceChecker; the implementation class is internal.
Shared Parser Helpers
common.tscontains TypeScript name and type-argument helpers shared across parser layers.documentationParser.tsconverts TypeScript documentation, JSDoc metadata, and parameter documentation into model documentation nodes.
Requirements
- Node.js: >= 22
License
This project is licensed under the terms of the MIT license.
Acknowledgments
This project was started as a fork of typescript-to-proptypes created by Kristoffer K..
