Library with TypeScript
In this page:
Core Concept
Writing a publishable library in TypeScript means the compiler generates both the runtime .js output and .d.ts declaration files, so anyone who installs your package gets full type information for free without needing your source.
Example: Core Concept
export function parseDate(input: string): Date {
return new Date(input);
}
console.log(parseDate("2024-01-01"));
Basic Setup
A basic setup sets "declaration": true and "outDir": "dist" in tsconfig.json, and package.json's "types" field points at the emitted .d.ts entry file so consumers' editors pick it up automatically.
Example: Basic Setup
// tsconfig.json: { "compilerOptions": { "declaration": true, "outDir": "dist" } }
// package.json: { "types": "dist/index.d.ts" }
console.log("declaration output ships .d.ts files alongside compiled JS");
Typed Example
A typed example: exporting export function parseDate(input: string): Date from your library means a consumer's editor shows the exact parameter and return types on hover, with no separate @types package needed.
Example: Typed Example
export function parseDate(input: string): Date {
return new Date(input);
}
// A consumer's editor shows this exact signature on hover, no @types needed.
console.log(parseDate("2024-06-15").getFullYear());
Project Usage
In a real project, keeping your library's public API surface intentionally small and well-typed (rather than exporting every internal helper) makes future changes easier, since anything not exported can be freely refactored without breaking consumers.
Example: Project Usage
// Only export the small, intentional public surface:
export function formatCurrency(amount: number): string {
return `$${amount.toFixed(2)}`;
}
// internalHelper() stays unexported and freely refactorable.
console.log(formatCurrency(19.99));
Best Practices
Run your library's own test suite against the *compiled* .d.ts output occasionally (not just the source), since a valid-looking source file can sometimes produce declaration output that doesn't actually match your intent.
Example: Best Practices
export interface LibraryConfig {
apiKey: string;
}
export function configure(config: LibraryConfig): void {
console.log("Configured with", config.apiKey);
}
// Occasionally test against the compiled .d.ts output, not just source.
configure({ apiKey: "abc" });
Chapter Quiz — Complete all 14 topics to unlock
0/14 topics done
Complete these topics first:
- Todo App with TypeScript
- REST API with Express + TypeScript
- React Dashboard with TypeScript
- CLI Tool with TypeScript
- Library with TypeScript
- Full Stack TypeScript App
- TypeScript Design System
- TypeScript Monorepo Project
- Authentication System
- Real-time App with Socket.io
- GraphQL API with TypeScript
- Microservices with TypeScript
- TypeScript Best Practices Review
- What to Learn Next