Prerequisites
- Understanding of TypeScript module systems and declarations π
- Knowledge of JavaScript modules and library integration β‘
- Familiarity with declaration files (.d.ts) π»
What you'll learn
- Master ambient module declarations and advanced patterns π―
- Create comprehensive type definitions for external libraries ποΈ
- Build flexible module definition systems for large projects π
- Integrate seamlessly with JavaScript ecosystems and tooling β¨
π― Introduction
Welcome to the diplomatic embassy of TypeScriptβs type system! π If TypeScript were a country with its own language and customs, then ambient modules are like diplomatic missions that allow foreign JavaScript libraries to communicate and integrate seamlessly with TypeScriptβs strict type system - they provide a bridge between the loosely-typed JavaScript world and TypeScriptβs type-safe environment.
Ambient modules allow you to declare types for external JavaScript libraries, Node.js modules, and any code that exists outside your TypeScript compilation but needs type information. Theyβre essential for working with third-party libraries, creating type definitions for npm packages, and building robust type systems that can encompass entire JavaScript ecosystems.
By the end of this tutorial, youβll be a master diplomat of ambient modules, capable of creating comprehensive type definitions that make any JavaScript library feel like a first-class TypeScript citizen while maintaining flexibility and compatibility across different environments. Letβs master the art of ambient module diplomacy! π
π Understanding Ambient Modules
π€ What Are Ambient Modules?
Ambient modules are TypeScript declarations that describe the shape and structure of modules that exist at runtime but donβt have TypeScript source code. They use the declare module
syntax to define types for external libraries, allowing TypeScript to understand and type-check code that uses these modules.
// π Basic ambient module declarations
// Declaring a simple external library
declare module 'simple-library' {
export function greet(name: string): string;
export function calculate(a: number, b: number): number;
export const version: string;
}
// Using the declared module
import { greet, calculate, version } from 'simple-library';
const message = greet('TypeScript'); // Type: string
const result = calculate(10, 20); // Type: number
console.log(`Version: ${version}`); // Type: string
// π― Declaring modules with default exports
declare module 'logger-lib' {
interface LoggerOptions {
level: 'debug' | 'info' | 'warn' | 'error';
format: 'json' | 'text';
output: 'console' | 'file';
}
interface Logger {
debug(message: string, meta?: any): void;
info(message: string, meta?: any): void;
warn(message: string, meta?: any): void;
error(message: string, error?: Error): void;
child(context: Record<string, any>): Logger;
}
function createLogger(name: string, options?: LoggerOptions): Logger;
export = createLogger; // CommonJS default export
}
// Usage with CommonJS-style import
import createLogger = require('logger-lib');
const logger = createLogger('App', {
level: 'info',
format: 'json',
output: 'console'
});
logger.info('Application started');
// π§ Declaring modules with mixed export styles
declare module 'utility-belt' {
// Named exports
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number,
immediate?: boolean
): T;
export function throttle<T extends (...args: any[]) => any>(
func: T,
limit: number
): T;
export function deepClone<T>(obj: T): T;
// Default export
interface UtilityBelt {
string: StringUtils;
array: ArrayUtils;
object: ObjectUtils;
date: DateUtils;
}
interface StringUtils {
capitalize(str: string): string;
kebabCase(str: string): string;
camelCase(str: string): string;
truncate(str: string, length: number): string;
}
interface ArrayUtils {
chunk<T>(array: T[], size: number): T[][];
flatten<T>(array: T[][]): T[];
unique<T>(array: T[]): T[];
groupBy<T>(array: T[], key: keyof T): Record<string, T[]>;
}
interface ObjectUtils {
pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;
merge<T, U>(target: T, source: U): T & U;
isEmpty(obj: any): boolean;
}
interface DateUtils {
format(date: Date, pattern: string): string;
addDays(date: Date, days: number): Date;
diffInDays(date1: Date, date2: Date): number;
isWeekend(date: Date): boolean;
}
const utils: UtilityBelt;
export default utils;
}
// Usage with mixed imports
import utils, { debounce, throttle, deepClone } from 'utility-belt';
// Use default export
const formattedDate = utils.date.format(new Date(), 'YYYY-MM-DD');
const chunks = utils.array.chunk([1, 2, 3, 4, 5], 2);
// Use named exports
const debouncedHandler = debounce(() => console.log('Debounced'), 300);
const clonedObject = deepClone({ a: 1, b: 2 });
// β¨ Declaring modules with complex types
declare module 'advanced-http-client' {
interface RequestConfig {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
url: string;
headers?: Record<string, string>;
params?: Record<string, any>;
data?: any;
timeout?: number;
retries?: number;
validateStatus?: (status: number) => boolean;
}
interface ResponseData<T = any> {
data: T;
status: number;
statusText: string;
headers: Record<string, string>;
config: RequestConfig;
}
interface UploadConfig extends RequestConfig {
onUploadProgress?: (progressEvent: ProgressEvent) => void;
maxBodyLength?: number;
maxContentLength?: number;
}
interface DownloadConfig extends RequestConfig {
onDownloadProgress?: (progressEvent: ProgressEvent) => void;
responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream';
}
interface InterceptorManager<V> {
use(onFulfilled?: (value: V) => V | Promise<V>, onRejected?: (error: any) => any): number;
eject(id: number): void;
}
interface HttpClient {
request<T = any>(config: RequestConfig): Promise<ResponseData<T>>;
get<T = any>(url: string, config?: RequestConfig): Promise<ResponseData<T>>;
post<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ResponseData<T>>;
put<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ResponseData<T>>;
delete<T = any>(url: string, config?: RequestConfig): Promise<ResponseData<T>>;
upload<T = any>(url: string, data: FormData, config?: UploadConfig): Promise<ResponseData<T>>;
download(url: string, config?: DownloadConfig): Promise<ResponseData<ArrayBuffer>>;
interceptors: {
request: InterceptorManager<RequestConfig>;
response: InterceptorManager<ResponseData>;
};
}
interface ClientFactory {
create(baseConfig?: RequestConfig): HttpClient;
defaults: RequestConfig;
}
const client: HttpClient;
const factory: ClientFactory;
export { RequestConfig, ResponseData, UploadConfig, DownloadConfig, HttpClient };
export { client as default, factory };
}
// Advanced usage
import httpClient, { factory, RequestConfig, ResponseData } from 'advanced-http-client';
// Configure default client
httpClient.interceptors.request.use((config) => {
config.headers = { ...config.headers, 'Authorization': 'Bearer token' };
return config;
});
// Create custom client
const apiClient = factory.create({
url: 'https://api.example.com',
timeout: 30000,
headers: { 'Content-Type': 'application/json' }
});
interface User {
id: string;
name: string;
email: string;
}
const fetchUser = async (id: string): Promise<User> => {
const response = await apiClient.get<User>(`/users/${id}`);
return response.data;
};
ποΈ Advanced Ambient Module Patterns
// π Conditional module declarations based on environment
// Node.js specific modules
declare module 'node-specific-lib' {
import { EventEmitter } from 'events';
import { Readable, Writable } from 'stream';
interface FileSystemWatcher extends EventEmitter {
close(): void;
add(path: string): void;
remove(path: string): void;
}
interface WatchOptions {
persistent?: boolean;
recursive?: boolean;
encoding?: BufferEncoding;
}
interface ProcessManager {
spawn(command: string, args: string[], options?: SpawnOptions): ChildProcess;
exec(command: string, options?: ExecOptions): Promise<ExecResult>;
kill(pid: number, signal?: string): boolean;
list(): ProcessInfo[];
}
interface SpawnOptions {
cwd?: string;
env?: Record<string, string>;
stdio?: 'pipe' | 'ignore' | 'inherit';
shell?: boolean;
timeout?: number;
}
interface ExecOptions extends SpawnOptions {
maxBuffer?: number;
}
interface ExecResult {
stdout: string;
stderr: string;
code: number;
}
interface ChildProcess extends EventEmitter {
pid?: number;
stdin: Writable;
stdout: Readable;
stderr: Readable;
kill(signal?: string): boolean;
}
interface ProcessInfo {
pid: number;
name: string;
cpu: number;
memory: number;
startTime: Date;
}
export function watch(path: string, options?: WatchOptions): FileSystemWatcher;
export const processes: ProcessManager;
export function isNode(): true;
}
// Browser specific modules
declare module 'browser-specific-lib' {
interface BrowserInfo {
name: string;
version: string;
engine: string;
os: string;
}
interface GeolocationService {
getCurrentPosition(options?: PositionOptions): Promise<GeolocationPosition>;
watchPosition(
callback: (position: GeolocationPosition) => void,
errorCallback?: (error: GeolocationPositionError) => void,
options?: PositionOptions
): number;
clearWatch(watchId: number): void;
}
interface StorageManager {
local: Storage;
session: Storage;
cookie: CookieManager;
}
interface CookieManager {
get(name: string): string | null;
set(name: string, value: string, options?: CookieOptions): void;
remove(name: string): void;
clear(): void;
}
interface CookieOptions {
expires?: Date;
maxAge?: number;
domain?: string;
path?: string;
secure?: boolean;
httpOnly?: boolean;
sameSite?: 'strict' | 'lax' | 'none';
}
interface NotificationService {
request(): Promise<NotificationPermission>;
show(title: string, options?: NotificationOptions): Notification;
isSupported(): boolean;
}
export function getBrowserInfo(): BrowserInfo;
export const geolocation: GeolocationService;
export const storage: StorageManager;
export const notifications: NotificationService;
export function isBrowser(): true;
}
// Universal modules (work in both environments)
declare module 'universal-lib' {
interface NetworkAdapter {
fetch(url: string, options?: RequestInit): Promise<Response>;
isOnline(): boolean;
getConnectionType(): ConnectionType;
}
type ConnectionType = 'ethernet' | 'wifi' | 'cellular' | 'bluetooth' | 'unknown';
interface CryptoAdapter {
randomBytes(size: number): Uint8Array;
hash(algorithm: string, data: string | Uint8Array): Promise<string>;
encrypt(data: string, key: string, algorithm?: string): Promise<string>;
decrypt(data: string, key: string, algorithm?: string): Promise<string>;
}
interface EventBus {
on<T = any>(event: string, handler: (data: T) => void): () => void;
off(event: string, handler: Function): void;
emit<T = any>(event: string, data?: T): void;
once<T = any>(event: string, handler: (data: T) => void): () => void;
clear(event?: string): void;
}
interface TaskScheduler {
schedule(task: () => void | Promise<void>, delay: number): TaskHandle;
scheduleRepeating(task: () => void | Promise<void>, interval: number): TaskHandle;
immediate(task: () => void | Promise<void>): TaskHandle;
cancel(handle: TaskHandle): boolean;
cancelAll(): void;
}
interface TaskHandle {
id: string;
cancel(): boolean;
isPending(): boolean;
}
export const network: NetworkAdapter;
export const crypto: CryptoAdapter;
export function createEventBus(): EventBus;
export const scheduler: TaskScheduler;
}
// π§ Wildcard module declarations
declare module '*.json' {
const content: any;
export default content;
}
declare module '*.css' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.scss' {
const classes: { [key: string]: string };
export default classes;
}
declare module '*.svg' {
const content: string;
export default content;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.jpg' {
const src: string;
export default src;
}
// Usage of wildcard declarations
import config from './config.json'; // Type: any
import styles from './component.css'; // Type: { [key: string]: string }
import logo from './logo.svg'; // Type: string
import image from './hero.png'; // Type: string
// π¨ Plugin-based module declarations
declare module 'plugin-system' {
interface Plugin<TOptions = any> {
name: string;
version: string;
install(app: Application, options?: TOptions): void | Promise<void>;
uninstall?(app: Application): void | Promise<void>;
}
interface PluginManager {
register<T = any>(plugin: Plugin<T>, options?: T): Promise<void>;
unregister(pluginName: string): Promise<void>;
get(pluginName: string): Plugin | undefined;
list(): Plugin[];
isRegistered(pluginName: string): boolean;
}
interface Application {
plugins: PluginManager;
use<T = any>(plugin: Plugin<T>, options?: T): Promise<Application>;
boot(): Promise<void>;
shutdown(): Promise<void>;
}
interface MiddlewareContext {
request: any;
response: any;
next(): Promise<void>;
}
type Middleware = (context: MiddlewareContext) => void | Promise<void>;
interface RouterPlugin extends Plugin {
get(path: string, ...middleware: Middleware[]): void;
post(path: string, ...middleware: Middleware[]): void;
put(path: string, ...middleware: Middleware[]): void;
delete(path: string, ...middleware: Middleware[]): void;
use(path: string, ...middleware: Middleware[]): void;
}
interface DatabasePlugin extends Plugin {
connect(): Promise<void>;
disconnect(): Promise<void>;
query<T = any>(sql: string, params?: any[]): Promise<T[]>;
transaction<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>;
}
interface Transaction {
query<T = any>(sql: string, params?: any[]): Promise<T[]>;
commit(): Promise<void>;
rollback(): Promise<void>;
}
export function createApp(): Application;
export { Plugin, PluginManager, Application, Middleware, RouterPlugin, DatabasePlugin };
}
// Plugin usage
import { createApp, Plugin, RouterPlugin, DatabasePlugin } from 'plugin-system';
const routerPlugin: RouterPlugin = {
name: 'router',
version: '1.0.0',
install(app) {
// Router installation logic
},
get(path, ...middleware) {
// GET route handler
},
post(path, ...middleware) {
// POST route handler
},
put(path, ...middleware) {
// PUT route handler
},
delete(path, ...middleware) {
// DELETE route handler
},
use(path, ...middleware) {
// Middleware registration
}
};
const dbPlugin: DatabasePlugin = {
name: 'database',
version: '2.0.0',
install(app) {
// Database installation logic
},
async connect() {
// Connection logic
},
async disconnect() {
// Disconnection logic
},
async query<T>(sql: string, params?: any[]): Promise<T[]> {
// Query implementation
return [];
},
async transaction<T>(callback: (tx: any) => Promise<T>): Promise<T> {
// Transaction implementation
return callback({});
}
};
const app = createApp();
await app.use(routerPlugin);
await app.use(dbPlugin, { connectionString: 'postgresql://...' });
await app.boot();
π οΈ Building an Ambient Module Management System
Letβs create a comprehensive system for managing ambient module declarations:
// ποΈ Ambient Module Declaration Management System
namespace AmbientModules {
// π Core interfaces for ambient module management
export interface ModuleRegistry {
modules: Map<string, ModuleDeclaration>;
patterns: Map<string, PatternDeclaration>;
dependencies: Map<string, ModuleDependency[]>;
versions: Map<string, VersionInfo>;
metadata: RegistryMetadata;
}
export interface ModuleDeclaration {
name: string;
version: string;
description: string;
exports: ExportDeclaration[];
defaultExport?: DefaultExportDeclaration;
dependencies: string[];
peerDependencies: string[];
environments: Environment[];
license: string;
author: string;
repository?: string;
tags: string[];
deprecated?: DeprecationInfo;
createdAt: Date;
updatedAt: Date;
}
export interface ExportDeclaration {
name: string;
type: ExportType;
signature: string;
description: string;
examples: string[];
since?: string;
deprecated?: DeprecationInfo;
}
export type ExportType =
| 'function'
| 'class'
| 'interface'
| 'type'
| 'constant'
| 'variable'
| 'namespace';
export interface DefaultExportDeclaration {
type: 'function' | 'class' | 'object' | 'value';
signature: string;
description: string;
examples: string[];
}
export interface PatternDeclaration {
pattern: string;
description: string;
exampleFiles: string[];
exportType: string;
commonUsage: string[];
relatedPatterns: string[];
}
export interface ModuleDependency {
name: string;
version: string;
type: 'runtime' | 'peer' | 'dev';
optional: boolean;
}
export interface VersionInfo {
current: string;
available: string[];
changelog: ChangelogEntry[];
compatibility: CompatibilityInfo;
}
export interface ChangelogEntry {
version: string;
date: Date;
changes: Change[];
}
export interface Change {
type: 'added' | 'changed' | 'deprecated' | 'removed' | 'fixed' | 'security';
description: string;
breaking: boolean;
migration?: string;
}
export interface CompatibilityInfo {
typescript: string[];
node: string[];
browsers: BrowserSupport[];
}
export interface BrowserSupport {
name: string;
version: string;
supported: boolean;
notes?: string;
}
export type Environment = 'node' | 'browser' | 'web-worker' | 'electron' | 'react-native';
export interface DeprecationInfo {
since: string;
reason: string;
replacement?: string;
removalVersion?: string;
}
export interface RegistryMetadata {
totalModules: number;
totalPatterns: number;
lastUpdated: Date;
version: string;
maintainers: string[];
}
// π§ Module Declaration Generator
export class DeclarationGenerator {
private registry: ModuleRegistry;
private analyzer: ModuleAnalyzer;
private validator: DeclarationValidator;
constructor() {
this.registry = this.initializeRegistry();
this.analyzer = new ModuleAnalyzer();
this.validator = new DeclarationValidator();
}
// π Generate ambient module declaration
generateDeclaration(moduleInfo: ModuleInfo): GenerationResult {
console.log(`π Generating ambient declaration for: ${moduleInfo.name}`);
try {
// Analyze the module
const analysis = this.analyzer.analyzeModule(moduleInfo);
// Validate the analysis
const validation = this.validator.validate(analysis);
if (!validation.isValid) {
return {
success: false,
errors: validation.errors,
warnings: validation.warnings
};
}
// Generate the declaration
const declaration = this.createDeclaration(analysis);
// Generate TypeScript code
const declarationCode = this.generateTypeScriptCode(declaration);
// Register the module
this.registry.modules.set(moduleInfo.name, declaration);
return {
success: true,
declaration,
code: declarationCode,
warnings: validation.warnings
};
} catch (error) {
return {
success: false,
errors: [`Generation failed: ${error.message}`]
};
}
}
// π Analyze existing module
analyzeExistingModule(moduleName: string): AnalysisResult {
console.log(`π Analyzing existing module: ${moduleName}`);
const module = this.registry.modules.get(moduleName);
if (!module) {
return {
found: false,
error: `Module ${moduleName} not found in registry`
};
}
const dependencies = this.analyzeDependencies(module);
const usage = this.analyzeUsagePatterns(module);
const compatibility = this.analyzeCompatibility(module);
return {
found: true,
module,
dependencies,
usage,
compatibility,
suggestions: this.generateSuggestions(module, dependencies, usage)
};
}
// π― Generate wildcard pattern declaration
generatePatternDeclaration(pattern: PatternInfo): PatternResult {
console.log(`π― Generating pattern declaration for: ${pattern.pattern}`);
const patternDeclaration: PatternDeclaration = {
pattern: pattern.pattern,
description: pattern.description,
exampleFiles: pattern.exampleFiles,
exportType: pattern.exportType,
commonUsage: pattern.commonUsage,
relatedPatterns: []
};
const code = this.generatePatternCode(patternDeclaration);
this.registry.patterns.set(pattern.pattern, patternDeclaration);
return {
success: true,
declaration: patternDeclaration,
code
};
}
// π Update module declaration
updateDeclaration(moduleName: string, updates: Partial<ModuleDeclaration>): UpdateResult {
console.log(`π Updating declaration for: ${moduleName}`);
const existing = this.registry.modules.get(moduleName);
if (!existing) {
return {
success: false,
error: `Module ${moduleName} not found`
};
}
const updated = { ...existing, ...updates, updatedAt: new Date() };
// Validate the update
const validation = this.validator.validateUpdate(existing, updated);
if (!validation.isValid) {
return {
success: false,
error: 'Update validation failed',
details: validation.errors
};
}
this.registry.modules.set(moduleName, updated);
return {
success: true,
declaration: updated,
changes: this.detectChanges(existing, updated)
};
}
// π Generate comprehensive report
generateRegistryReport(): RegistryReport {
console.log('π Generating comprehensive registry report');
const modules = Array.from(this.registry.modules.values());
const patterns = Array.from(this.registry.patterns.values());
return {
summary: {
totalModules: modules.length,
totalPatterns: patterns.length,
totalExports: modules.reduce((sum, m) => sum + m.exports.length, 0),
environmentSupport: this.calculateEnvironmentSupport(modules),
lastUpdated: this.registry.metadata.lastUpdated
},
popularModules: this.findPopularModules(modules),
deprecatedModules: modules.filter(m => m.deprecated),
outdatedModules: this.findOutdatedModules(modules),
dependencyGraph: this.buildDependencyGraph(modules),
recommendedUpdates: this.generateUpdateRecommendations(modules),
qualityMetrics: this.calculateQualityMetrics(modules),
generatedAt: new Date()
};
}
// π§ Private helper methods
private initializeRegistry(): ModuleRegistry {
return {
modules: new Map(),
patterns: new Map(),
dependencies: new Map(),
versions: new Map(),
metadata: {
totalModules: 0,
totalPatterns: 0,
lastUpdated: new Date(),
version: '1.0.0',
maintainers: ['System']
}
};
}
private createDeclaration(analysis: ModuleAnalysis): ModuleDeclaration {
return {
name: analysis.name,
version: analysis.version,
description: analysis.description,
exports: analysis.exports.map(exp => ({
name: exp.name,
type: exp.type,
signature: exp.signature,
description: exp.description || '',
examples: exp.examples || [],
since: analysis.version
})),
defaultExport: analysis.defaultExport ? {
type: analysis.defaultExport.type,
signature: analysis.defaultExport.signature,
description: analysis.defaultExport.description || '',
examples: analysis.defaultExport.examples || []
} : undefined,
dependencies: analysis.dependencies,
peerDependencies: analysis.peerDependencies,
environments: analysis.environments,
license: analysis.license || 'Unknown',
author: analysis.author || 'Unknown',
repository: analysis.repository,
tags: analysis.tags || [],
createdAt: new Date(),
updatedAt: new Date()
};
}
private generateTypeScriptCode(declaration: ModuleDeclaration): string {
const lines: string[] = [];
lines.push(`// Type definitions for ${declaration.name} ${declaration.version}`);
lines.push(`// Project: ${declaration.repository || 'Unknown'}`);
lines.push(`// Definitions by: ${declaration.author}`);
lines.push('');
lines.push(`declare module '${declaration.name}' {`);
// Generate interfaces for complex types
const interfaces = this.extractInterfaces(declaration);
for (const iface of interfaces) {
lines.push(` ${iface}`);
}
// Generate exports
for (const exp of declaration.exports) {
lines.push(` ${this.generateExportCode(exp)}`);
}
// Generate default export
if (declaration.defaultExport) {
lines.push(` ${this.generateDefaultExportCode(declaration.defaultExport)}`);
}
lines.push('}');
return lines.join('\n');
}
private generatePatternCode(pattern: PatternDeclaration): string {
return `declare module '${pattern.pattern}' {\n ${pattern.exportType}\n}`;
}
private generateExportCode(exp: ExportDeclaration): string {
switch (exp.type) {
case 'function':
return `export ${exp.signature};`;
case 'class':
return `export ${exp.signature};`;
case 'interface':
return `export ${exp.signature};`;
case 'type':
return `export ${exp.signature};`;
case 'constant':
case 'variable':
return `export ${exp.signature};`;
case 'namespace':
return `export namespace ${exp.name} { ${exp.signature} }`;
default:
return `export ${exp.signature};`;
}
}
private generateDefaultExportCode(defaultExp: DefaultExportDeclaration): string {
switch (defaultExp.type) {
case 'function':
return `export = ${defaultExp.signature};`;
case 'class':
return `export = ${defaultExp.signature};`;
case 'object':
return `declare const _default: ${defaultExp.signature}; export = _default;`;
case 'value':
return `declare const _default: ${defaultExp.signature}; export = _default;`;
default:
return `export = ${defaultExp.signature};`;
}
}
private extractInterfaces(declaration: ModuleDeclaration): string[] {
// Extract interface definitions from signatures
const interfaces: string[] = [];
for (const exp of declaration.exports) {
if (exp.type === 'interface') {
interfaces.push(`interface ${exp.name} ${exp.signature}`);
}
}
return interfaces;
}
private analyzeDependencies(module: ModuleDeclaration): DependencyAnalysis {
return {
direct: module.dependencies,
peer: module.peerDependencies,
circular: [],
outdated: [],
security: []
};
}
private analyzeUsagePatterns(module: ModuleDeclaration): UsageAnalysis {
return {
mostUsedExports: [],
commonPatterns: [],
antiPatterns: [],
performanceImpact: 'low'
};
}
private analyzeCompatibility(module: ModuleDeclaration): CompatibilityAnalysis {
return {
typescript: [],
environments: module.environments,
breakingChanges: [],
migrationPaths: []
};
}
private generateSuggestions(
module: ModuleDeclaration,
dependencies: DependencyAnalysis,
usage: UsageAnalysis
): string[] {
const suggestions: string[] = [];
if (module.deprecated) {
suggestions.push(`Consider migrating to ${module.deprecated.replacement || 'an alternative'}`);
}
if (dependencies.outdated.length > 0) {
suggestions.push('Update outdated dependencies');
}
if (module.exports.length > 20) {
suggestions.push('Consider splitting large module into smaller modules');
}
return suggestions;
}
private detectChanges(old: ModuleDeclaration, updated: ModuleDeclaration): Change[] {
const changes: Change[] = [];
// Detect export changes
const oldExports = new Set(old.exports.map(e => e.name));
const newExports = new Set(updated.exports.map(e => e.name));
for (const exp of updated.exports) {
if (!oldExports.has(exp.name)) {
changes.push({
type: 'added',
description: `Added export: ${exp.name}`,
breaking: false
});
}
}
for (const exp of old.exports) {
if (!newExports.has(exp.name)) {
changes.push({
type: 'removed',
description: `Removed export: ${exp.name}`,
breaking: true
});
}
}
return changes;
}
private calculateEnvironmentSupport(modules: ModuleDeclaration[]): Record<Environment, number> {
const support: Record<Environment, number> = {
'node': 0,
'browser': 0,
'web-worker': 0,
'electron': 0,
'react-native': 0
};
for (const module of modules) {
for (const env of module.environments) {
support[env]++;
}
}
return support;
}
private findPopularModules(modules: ModuleDeclaration[]): ModuleDeclaration[] {
// Sort by some popularity metric (e.g., number of exports, tags, etc.)
return modules.slice(0, 10);
}
private findOutdatedModules(modules: ModuleDeclaration[]): ModuleDeclaration[] {
const now = new Date();
const threeMonthsAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);
return modules.filter(m => m.updatedAt < threeMonthsAgo);
}
private buildDependencyGraph(modules: ModuleDeclaration[]): DependencyGraph {
return {
nodes: modules.map(m => ({ id: m.name, label: m.name })),
edges: modules.flatMap(m =>
m.dependencies.map(dep => ({ from: m.name, to: dep }))
)
};
}
private generateUpdateRecommendations(modules: ModuleDeclaration[]): UpdateRecommendation[] {
return modules.map(module => ({
moduleName: module.name,
currentVersion: module.version,
recommendedVersion: 'latest',
priority: 'medium',
reason: 'Regular maintenance update'
}));
}
private calculateQualityMetrics(modules: ModuleDeclaration[]): QualityMetrics {
const totalModules = modules.length;
const documented = modules.filter(m => m.description && m.description.length > 10).length;
const withExamples = modules.filter(m =>
m.exports.some(e => e.examples && e.examples.length > 0)
).length;
return {
documentationCoverage: totalModules > 0 ? documented / totalModules : 0,
exampleCoverage: totalModules > 0 ? withExamples / totalModules : 0,
averageExports: totalModules > 0 ?
modules.reduce((sum, m) => sum + m.exports.length, 0) / totalModules : 0,
deprecationRate: totalModules > 0 ?
modules.filter(m => m.deprecated).length / totalModules : 0
};
}
}
// π Supporting classes and interfaces
class ModuleAnalyzer {
analyzeModule(moduleInfo: ModuleInfo): ModuleAnalysis {
// Analyze module structure, exports, dependencies, etc.
return {
name: moduleInfo.name,
version: moduleInfo.version || '1.0.0',
description: moduleInfo.description || '',
exports: this.extractExports(moduleInfo),
defaultExport: this.extractDefaultExport(moduleInfo),
dependencies: moduleInfo.dependencies || [],
peerDependencies: moduleInfo.peerDependencies || [],
environments: this.detectEnvironments(moduleInfo),
license: moduleInfo.license,
author: moduleInfo.author,
repository: moduleInfo.repository,
tags: moduleInfo.tags
};
}
private extractExports(moduleInfo: ModuleInfo): ExportInfo[] {
// Extract export information from module
return moduleInfo.exports || [];
}
private extractDefaultExport(moduleInfo: ModuleInfo): DefaultExportInfo | undefined {
return moduleInfo.defaultExport;
}
private detectEnvironments(moduleInfo: ModuleInfo): Environment[] {
// Detect supported environments based on module characteristics
return moduleInfo.environments || ['node', 'browser'];
}
}
class DeclarationValidator {
validate(analysis: ModuleAnalysis): ValidationResult {
const errors: string[] = [];
const warnings: string[] = [];
// Validate module name
if (!analysis.name || analysis.name.trim() === '') {
errors.push('Module name cannot be empty');
}
// Validate exports
if (!analysis.exports || analysis.exports.length === 0) {
warnings.push('Module has no exports');
}
// Validate export signatures
for (const exp of analysis.exports) {
if (!exp.signature || exp.signature.trim() === '') {
errors.push(`Export ${exp.name} has no signature`);
}
}
return {
isValid: errors.length === 0,
errors,
warnings
};
}
validateUpdate(existing: ModuleDeclaration, updated: ModuleDeclaration): ValidationResult {
const errors: string[] = [];
const warnings: string[] = [];
// Check for breaking changes
const removedExports = existing.exports.filter(oldExp =>
!updated.exports.find(newExp => newExp.name === oldExp.name)
);
if (removedExports.length > 0) {
warnings.push(`Removed exports: ${removedExports.map(e => e.name).join(', ')}`);
}
return {
isValid: errors.length === 0,
errors,
warnings
};
}
}
// π Supporting interfaces
interface ModuleInfo {
name: string;
version?: string;
description?: string;
exports?: ExportInfo[];
defaultExport?: DefaultExportInfo;
dependencies?: string[];
peerDependencies?: string[];
environments?: Environment[];
license?: string;
author?: string;
repository?: string;
tags?: string[];
}
interface ExportInfo {
name: string;
type: ExportType;
signature: string;
description?: string;
examples?: string[];
}
interface DefaultExportInfo {
type: 'function' | 'class' | 'object' | 'value';
signature: string;
description?: string;
examples?: string[];
}
interface ModuleAnalysis {
name: string;
version: string;
description: string;
exports: ExportInfo[];
defaultExport?: DefaultExportInfo;
dependencies: string[];
peerDependencies: string[];
environments: Environment[];
license?: string;
author?: string;
repository?: string;
tags?: string[];
}
interface ValidationResult {
isValid: boolean;
errors: string[];
warnings: string[];
}
interface GenerationResult {
success: boolean;
declaration?: ModuleDeclaration;
code?: string;
errors?: string[];
warnings?: string[];
}
interface AnalysisResult {
found: boolean;
module?: ModuleDeclaration;
dependencies?: DependencyAnalysis;
usage?: UsageAnalysis;
compatibility?: CompatibilityAnalysis;
suggestions?: string[];
error?: string;
}
interface PatternInfo {
pattern: string;
description: string;
exampleFiles: string[];
exportType: string;
commonUsage: string[];
}
interface PatternResult {
success: boolean;
declaration?: PatternDeclaration;
code?: string;
error?: string;
}
interface UpdateResult {
success: boolean;
declaration?: ModuleDeclaration;
changes?: Change[];
error?: string;
details?: string[];
}
interface RegistryReport {
summary: RegistrySummary;
popularModules: ModuleDeclaration[];
deprecatedModules: ModuleDeclaration[];
outdatedModules: ModuleDeclaration[];
dependencyGraph: DependencyGraph;
recommendedUpdates: UpdateRecommendation[];
qualityMetrics: QualityMetrics;
generatedAt: Date;
}
interface RegistrySummary {
totalModules: number;
totalPatterns: number;
totalExports: number;
environmentSupport: Record<Environment, number>;
lastUpdated: Date;
}
interface DependencyAnalysis {
direct: string[];
peer: string[];
circular: string[];
outdated: string[];
security: string[];
}
interface UsageAnalysis {
mostUsedExports: string[];
commonPatterns: string[];
antiPatterns: string[];
performanceImpact: 'low' | 'medium' | 'high';
}
interface CompatibilityAnalysis {
typescript: string[];
environments: Environment[];
breakingChanges: string[];
migrationPaths: string[];
}
interface DependencyGraph {
nodes: Array<{ id: string; label: string }>;
edges: Array<{ from: string; to: string }>;
}
interface UpdateRecommendation {
moduleName: string;
currentVersion: string;
recommendedVersion: string;
priority: 'low' | 'medium' | 'high';
reason: string;
}
interface QualityMetrics {
documentationCoverage: number;
exampleCoverage: number;
averageExports: number;
deprecationRate: number;
}
}
// π Usage examples with the management system
const declarationGenerator = new AmbientModules.DeclarationGenerator();
// Generate declaration for a new module
const moduleInfo: AmbientModules.ModuleInfo = {
name: 'awesome-utility',
version: '2.1.0',
description: 'An awesome utility library with many helpful functions',
exports: [
{
name: 'debounce',
type: 'function',
signature: 'function debounce<T extends (...args: any[]) => any>(func: T, wait: number): T',
description: 'Creates a debounced function that delays invoking func',
examples: ['const debouncedFn = debounce(myFunction, 300);']
},
{
name: 'throttle',
type: 'function',
signature: 'function throttle<T extends (...args: any[]) => any>(func: T, limit: number): T',
description: 'Creates a throttled function that only invokes func at most once per every limit milliseconds',
examples: ['const throttledFn = throttle(myFunction, 1000);']
}
],
environments: ['node', 'browser'],
license: 'MIT',
author: 'Utility Team'
};
const result = declarationGenerator.generateDeclaration(moduleInfo);
if (result.success) {
console.log('Generated declaration:');
console.log(result.code);
} else {
console.error('Generation failed:', result.errors);
}
// Generate pattern declaration
const patternInfo: AmbientModules.PatternInfo = {
pattern: '*.worker.ts',
description: 'Web Worker TypeScript files',
exampleFiles: ['main.worker.ts', 'data.worker.ts'],
exportType: 'const content: string; export default content;',
commonUsage: ['Web Workers', 'Background processing']
};
const patternResult = declarationGenerator.generatePatternDeclaration(patternInfo);
console.log('Pattern declaration:', patternResult.code);
// Generate comprehensive report
const report = declarationGenerator.generateRegistryReport();
console.log('Registry report:', report);
π¨ Real-World Ambient Module Examples
// π Comprehensive real-world ambient module declarations
// React ecosystem declarations
declare module 'react-awesome-components' {
import { ComponentType, ReactNode, CSSProperties } from 'react';
interface BaseProps {
className?: string;
style?: CSSProperties;
children?: ReactNode;
testId?: string;
}
interface ButtonProps extends BaseProps {
variant?: 'primary' | 'secondary' | 'danger' | 'success';
size?: 'small' | 'medium' | 'large';
disabled?: boolean;
loading?: boolean;
onClick?: (event: MouseEvent) => void;
type?: 'button' | 'submit' | 'reset';
leftIcon?: ReactNode;
rightIcon?: ReactNode;
}
interface ModalProps extends BaseProps {
isOpen: boolean;
onClose: () => void;
title?: string;
size?: 'small' | 'medium' | 'large' | 'fullscreen';
closeable?: boolean;
overlay?: boolean;
animation?: 'fade' | 'slide' | 'zoom' | 'none';
onAnimationComplete?: () => void;
}
interface FormProps extends BaseProps {
onSubmit: (data: Record<string, any>) => void | Promise<void>;
validation?: ValidationSchema;
initialValues?: Record<string, any>;
resetOnSubmit?: boolean;
disabled?: boolean;
}
interface ValidationSchema {
[field: string]: FieldValidation;
}
interface FieldValidation {
required?: boolean;
min?: number;
max?: number;
pattern?: RegExp;
custom?: (value: any) => string | null;
}
interface InputProps extends BaseProps {
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url';
placeholder?: string;
value?: string;
defaultValue?: string;
onChange?: (value: string) => void;
onBlur?: () => void;
onFocus?: () => void;
disabled?: boolean;
readonly?: boolean;
error?: string;
leftAddon?: ReactNode;
rightAddon?: ReactNode;
}
interface TableProps<T = any> extends BaseProps {
data: T[];
columns: TableColumn<T>[];
loading?: boolean;
pagination?: PaginationConfig;
sorting?: SortingConfig<T>;
selection?: SelectionConfig<T>;
rowKey?: keyof T | ((row: T) => string);
onRowClick?: (row: T, index: number) => void;
}
interface TableColumn<T> {
key: keyof T;
title: string;
render?: (value: any, row: T, index: number) => ReactNode;
sortable?: boolean;
width?: number | string;
align?: 'left' | 'center' | 'right';
fixed?: 'left' | 'right';
}
interface PaginationConfig {
page: number;
pageSize: number;
total: number;
showSizeChanger?: boolean;
showQuickJumper?: boolean;
onPageChange: (page: number, pageSize: number) => void;
}
interface SortingConfig<T> {
field?: keyof T;
direction?: 'asc' | 'desc';
onSort: (field: keyof T, direction: 'asc' | 'desc') => void;
}
interface SelectionConfig<T> {
selectedKeys: string[];
onSelectionChange: (selectedKeys: string[], selectedRows: T[]) => void;
multiple?: boolean;
}
export const Button: ComponentType<ButtonProps>;
export const Modal: ComponentType<ModalProps>;
export const Form: ComponentType<FormProps>;
export const Input: ComponentType<InputProps>;
export const Table: <T = any>(props: TableProps<T>) => JSX.Element;
// Theme provider
interface ThemeConfig {
colors: ColorPalette;
typography: Typography;
spacing: Spacing;
breakpoints: Breakpoints;
}
interface ColorPalette {
primary: string;
secondary: string;
success: string;
warning: string;
danger: string;
info: string;
light: string;
dark: string;
}
interface Typography {
fontFamily: string;
fontSize: Record<string, string>;
fontWeight: Record<string, number>;
lineHeight: Record<string, number>;
}
interface Spacing {
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
}
interface Breakpoints {
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
}
interface ThemeProviderProps {
theme: ThemeConfig;
children: ReactNode;
}
export const ThemeProvider: ComponentType<ThemeProviderProps>;
export const useTheme: () => ThemeConfig;
export const defaultTheme: ThemeConfig;
}
// Node.js ecosystem declarations
declare module 'super-server' {
import { EventEmitter } from 'events';
import { IncomingMessage, ServerResponse } from 'http';
import { Socket } from 'net';
interface ServerConfig {
port?: number;
host?: string;
https?: {
key: string;
cert: string;
};
cors?: CorsConfig;
rateLimit?: RateLimitConfig;
compression?: CompressionConfig;
static?: StaticConfig;
middleware?: Middleware[];
}
interface CorsConfig {
origin?: string | string[] | ((origin: string) => boolean);
methods?: string[];
allowedHeaders?: string[];
credentials?: boolean;
maxAge?: number;
}
interface RateLimitConfig {
windowMs: number;
max: number;
message?: string;
standardHeaders?: boolean;
legacyHeaders?: boolean;
}
interface CompressionConfig {
threshold?: number;
level?: number;
chunkSize?: number;
filter?: (req: Request, res: Response) => boolean;
}
interface StaticConfig {
root: string;
index?: string[];
maxAge?: number;
etag?: boolean;
lastModified?: boolean;
}
interface Request extends IncomingMessage {
params: Record<string, string>;
query: Record<string, string>;
body: any;
files?: UploadedFile[];
user?: any;
session?: SessionData;
ip: string;
ips: string[];
protocol: string;
secure: boolean;
xhr: boolean;
path: string;
originalUrl: string;
baseUrl: string;
// Helper methods
get(header: string): string | undefined;
accepts(types: string | string[]): string | false;
acceptsLanguages(languages: string | string[]): string | false;
acceptsEncodings(encodings: string | string[]): string | false;
acceptsCharsets(charsets: string | string[]): string | false;
is(type: string | string[]): string | false;
param(name: string, defaultValue?: any): any;
}
interface Response extends ServerResponse {
// Status methods
status(code: number): Response;
sendStatus(code: number): Response;
// Header methods
set(field: string, value: string): Response;
get(field: string): string | undefined;
append(field: string, value: string): Response;
type(type: string): Response;
// Response methods
send(body?: any): Response;
json(obj: any): Response;
redirect(url: string): Response;
redirect(status: number, url: string): Response;
render(view: string, locals?: Record<string, any>): Response;
cookie(name: string, value: string, options?: CookieOptions): Response;
clearCookie(name: string, options?: CookieOptions): Response;
// File methods
sendFile(path: string, options?: SendFileOptions): void;
download(path: string, filename?: string): void;
attachment(filename?: string): Response;
}
interface UploadedFile {
fieldname: string;
originalname: string;
encoding: string;
mimetype: string;
size: number;
buffer: Buffer;
stream: NodeJS.ReadableStream;
destination?: string;
filename?: string;
path?: string;
}
interface SessionData {
id: string;
[key: string]: any;
}
interface CookieOptions {
maxAge?: number;
signed?: boolean;
expires?: Date;
httpOnly?: boolean;
path?: string;
domain?: string;
secure?: boolean;
encode?: (val: string) => string;
sameSite?: boolean | 'lax' | 'strict' | 'none';
}
interface SendFileOptions {
maxAge?: number;
root?: string;
lastModified?: boolean;
headers?: Record<string, string>;
dotfiles?: 'allow' | 'deny' | 'ignore';
acceptRanges?: boolean;
cacheControl?: boolean;
immutable?: boolean;
}
type Middleware = (req: Request, res: Response, next: NextFunction) => void | Promise<void>;
type NextFunction = (error?: any) => void;
type RouteHandler = Middleware;
type ErrorHandler = (error: any, req: Request, res: Response, next: NextFunction) => void;
interface Router {
get(path: string, ...handlers: RouteHandler[]): Router;
post(path: string, ...handlers: RouteHandler[]): Router;
put(path: string, ...handlers: RouteHandler[]): Router;
delete(path: string, ...handlers: RouteHandler[]): Router;
patch(path: string, ...handlers: RouteHandler[]): Router;
head(path: string, ...handlers: RouteHandler[]): Router;
options(path: string, ...handlers: RouteHandler[]): Router;
use(path: string, ...handlers: Middleware[]): Router;
use(...handlers: Middleware[]): Router;
route(path: string): Route;
param(name: string, handler: (req: Request, res: Response, next: NextFunction, value: any) => void): Router;
}
interface Route {
get(...handlers: RouteHandler[]): Route;
post(...handlers: RouteHandler[]): Route;
put(...handlers: RouteHandler[]): Route;
delete(...handlers: RouteHandler[]): Route;
patch(...handlers: RouteHandler[]): Route;
head(...handlers: RouteHandler[]): Route;
options(...handlers: RouteHandler[]): Route;
all(...handlers: RouteHandler[]): Route;
}
interface Application extends Router {
listen(port?: number, hostname?: string, callback?: () => void): Server;
listen(port?: number, callback?: () => void): Server;
listen(callback?: () => void): Server;
set(setting: string, val: any): Application;
get(setting: string): any;
enabled(setting: string): boolean;
disabled(setting: string): boolean;
enable(setting: string): Application;
disable(setting: string): Application;
engine(ext: string, fn: Function): Application;
render(name: string, options?: Record<string, any>, callback?: (err: Error, html: string) => void): void;
locals: Record<string, any>;
mountpath: string | string[];
// Error handling
use(handler: ErrorHandler): Application;
}
interface Server extends EventEmitter {
close(callback?: (err?: Error) => void): Server;
listening: boolean;
maxHeadersCount: number;
timeout: number;
keepAliveTimeout: number;
address(): { port: number; family: string; address: string } | string | null;
getConnections(callback: (error: Error | null, count: number) => void): void;
on(event: 'connection', listener: (socket: Socket) => void): this;
on(event: 'error', listener: (err: Error) => void): this;
on(event: 'listening', listener: () => void): this;
on(event: 'close', listener: () => void): this;
}
function createApp(config?: ServerConfig): Application;
function createRouter(): Router;
// Middleware exports
namespace middleware {
function cors(options?: CorsConfig): Middleware;
function rateLimit(options: RateLimitConfig): Middleware;
function compression(options?: CompressionConfig): Middleware;
function static(root: string, options?: StaticConfig): Middleware;
function bodyParser(): Middleware;
function fileUpload(options?: FileUploadOptions): Middleware;
function session(options: SessionOptions): Middleware;
function logger(format?: string): Middleware;
}
interface FileUploadOptions {
limits?: {
fieldNameSize?: number;
fieldSize?: number;
fields?: number;
fileSize?: number;
files?: number;
parts?: number;
headerPairs?: number;
};
preserveExtension?: boolean;
uploadTimeout?: number;
createParentPath?: boolean;
}
interface SessionOptions {
secret: string;
resave?: boolean;
saveUninitialized?: boolean;
cookie?: CookieOptions;
store?: SessionStore;
name?: string;
rolling?: boolean;
unset?: 'destroy' | 'keep';
}
interface SessionStore {
get(sid: string, callback: (err: any, session?: SessionData) => void): void;
set(sid: string, session: SessionData, callback?: (err?: any) => void): void;
destroy(sid: string, callback?: (err?: any) => void): void;
}
export { createApp as default, createRouter, middleware };
export { Application, Router, Request, Response, Middleware, NextFunction, Server };
export { ServerConfig, CorsConfig, RateLimitConfig, CompressionConfig, StaticConfig };
}
// Database ecosystem declarations
declare module 'super-orm' {
interface ConnectionConfig {
type: 'postgres' | 'mysql' | 'sqlite' | 'mongodb';
host?: string;
port?: number;
username?: string;
password?: string;
database: string;
ssl?: boolean | SSLConfig;
pool?: PoolConfig;
logging?: boolean | ((query: string) => void);
synchronize?: boolean;
migrations?: string[];
}
interface SSLConfig {
ca?: string;
cert?: string;
key?: string;
rejectUnauthorized?: boolean;
}
interface PoolConfig {
min?: number;
max?: number;
idle?: number;
acquire?: number;
evict?: number;
}
interface QueryResult<T = any> {
rows: T[];
count: number;
affectedRows?: number;
insertId?: number;
raw?: any;
}
interface QueryOptions {
limit?: number;
offset?: number;
orderBy?: Record<string, 'ASC' | 'DESC'>;
groupBy?: string[];
having?: Record<string, any>;
lock?: 'FOR UPDATE' | 'FOR SHARE';
}
interface Transaction {
query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>;
commit(): Promise<void>;
rollback(): Promise<void>;
savepoint(name: string): Promise<void>;
rollbackToSavepoint(name: string): Promise<void>;
releaseSavepoint(name: string): Promise<void>;
}
interface Connection {
query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>;
transaction<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>;
close(): Promise<void>;
isConnected(): boolean;
// Schema operations
createTable(name: string, schema: TableSchema): Promise<void>;
dropTable(name: string): Promise<void>;
addColumn(table: string, column: string, definition: ColumnDefinition): Promise<void>;
dropColumn(table: string, column: string): Promise<void>;
createIndex(table: string, columns: string[], options?: IndexOptions): Promise<void>;
dropIndex(table: string, name: string): Promise<void>;
}
interface TableSchema {
[column: string]: ColumnDefinition;
}
interface ColumnDefinition {
type: ColumnType;
primaryKey?: boolean;
autoIncrement?: boolean;
nullable?: boolean;
unique?: boolean;
default?: any;
length?: number;
precision?: number;
scale?: number;
references?: {
table: string;
column: string;
onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT';
onUpdate?: 'CASCADE' | 'SET NULL' | 'RESTRICT';
};
}
type ColumnType =
| 'VARCHAR' | 'TEXT' | 'CHAR'
| 'INTEGER' | 'BIGINT' | 'DECIMAL' | 'FLOAT' | 'DOUBLE'
| 'BOOLEAN'
| 'DATE' | 'DATETIME' | 'TIMESTAMP' | 'TIME'
| 'JSON' | 'JSONB'
| 'BLOB' | 'BINARY';
interface IndexOptions {
unique?: boolean;
type?: 'BTREE' | 'HASH' | 'GIN' | 'GIST';
where?: string;
}
// Model system
interface Model<T = any> {
findById(id: any): Promise<T | null>;
findOne(conditions: Partial<T>): Promise<T | null>;
findMany(conditions?: Partial<T>, options?: QueryOptions): Promise<T[]>;
create(data: Partial<T>): Promise<T>;
update(id: any, data: Partial<T>): Promise<T>;
delete(id: any): Promise<boolean>;
count(conditions?: Partial<T>): Promise<number>;
// Relationships
hasOne<R>(model: Model<R>, foreignKey: string): Relation<T, R>;
hasMany<R>(model: Model<R>, foreignKey: string): Relation<T, R[]>;
belongsTo<R>(model: Model<R>, foreignKey: string): Relation<T, R>;
belongsToMany<R>(model: Model<R>, through: string): Relation<T, R[]>;
}
interface Relation<T, R> {
with(conditions?: any): Relation<T, R>;
select(fields: string[]): Relation<T, R>;
load(): Promise<R>;
}
interface ModelOptions {
tableName: string;
primaryKey?: string;
timestamps?: boolean;
softDeletes?: boolean;
validation?: ValidationRules;
}
interface ValidationRules {
[field: string]: ValidationRule[];
}
type ValidationRule =
| 'required'
| 'email'
| 'unique'
| { min: number }
| { max: number }
| { length: number }
| { pattern: RegExp }
| { custom: (value: any) => boolean | string };
// Migration system
interface Migration {
up(connection: Connection): Promise<void>;
down(connection: Connection): Promise<void>;
}
interface MigrationRunner {
run(): Promise<void>;
rollback(steps?: number): Promise<void>;
reset(): Promise<void>;
status(): Promise<MigrationStatus[]>;
}
interface MigrationStatus {
name: string;
executed: boolean;
executedAt?: Date;
}
function connect(config: ConnectionConfig): Promise<Connection>;
function createModel<T>(name: string, options: ModelOptions): Model<T>;
function createMigrationRunner(connection: Connection, migrationsPath: string): MigrationRunner;
export { connect as default };
export { ConnectionConfig, Connection, Model, Migration, MigrationRunner };
export { QueryResult, QueryOptions, Transaction, TableSchema, ColumnDefinition };
export { createModel, createMigrationRunner };
}
π§ͺ Testing Ambient Modules
// π§ͺ Comprehensive testing for ambient module declarations
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
describe('Ambient Module Declarations', () => {
describe('Module Import and Export Testing', () => {
it('should properly type simple module imports', async () => {
// Test that declared modules can be imported with correct types
// Mock a simple library module for testing
jest.doMock('simple-library', () => ({
greet: (name: string) => `Hello, ${name}!`,
calculate: (a: number, b: number) => a + b,
version: '1.0.0'
}));
const { greet, calculate, version } = await import('simple-library');
// Type checking through usage
const greeting = greet('TypeScript');
expect(typeof greeting).toBe('string');
expect(greeting).toBe('Hello, TypeScript!');
const result = calculate(5, 3);
expect(typeof result).toBe('number');
expect(result).toBe(8);
expect(typeof version).toBe('string');
expect(version).toBe('1.0.0');
});
it('should handle complex module structures', async () => {
// Mock utility belt module
const mockUtils = {
string: {
capitalize: (str: string) => str.charAt(0).toUpperCase() + str.slice(1),
kebabCase: (str: string) => str.toLowerCase().replace(/\s+/g, '-'),
camelCase: (str: string) => str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : ''),
truncate: (str: string, length: number) => str.length > length ? str.slice(0, length) + '...' : str
},
array: {
chunk: <T>(array: T[], size: number): T[][] => {
const chunks: T[][] = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
},
flatten: <T>(array: T[][]): T[] => array.flat(),
unique: <T>(array: T[]): T[] => [...new Set(array)],
groupBy: <T>(array: T[], key: keyof T): Record<string, T[]> => {
return array.reduce((groups, item) => {
const group = String(item[key]);
groups[group] = groups[group] || [];
groups[group].push(item);
return groups;
}, {} as Record<string, T[]>);
}
},
object: {
pick: <T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> => {
const result = {} as Pick<T, K>;
keys.forEach(key => {
if (key in obj) {
result[key] = obj[key];
}
});
return result;
},
omit: <T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> => {
const result = { ...obj };
keys.forEach(key => delete result[key]);
return result;
},
merge: <T, U>(target: T, source: U): T & U => ({ ...target, ...source }),
isEmpty: (obj: any): boolean => Object.keys(obj).length === 0
},
date: {
format: (date: Date, pattern: string) => date.toISOString(),
addDays: (date: Date, days: number) => new Date(date.getTime() + days * 24 * 60 * 60 * 1000),
diffInDays: (date1: Date, date2: Date) => Math.abs(date1.getTime() - date2.getTime()) / (24 * 60 * 60 * 1000),
isWeekend: (date: Date) => date.getDay() === 0 || date.getDay() === 6
}
};
const mockFunctions = {
debounce: <T extends (...args: any[]) => any>(func: T, wait: number): T => {
let timeout: NodeJS.Timeout;
return ((...args: any[]) => {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait);
}) as T;
},
throttle: <T extends (...args: any[]) => any>(func: T, limit: number): T => {
let inThrottle: boolean;
return ((...args: any[]) => {
if (!inThrottle) {
func(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}) as T;
},
deepClone: <T>(obj: T): T => JSON.parse(JSON.stringify(obj))
};
jest.doMock('utility-belt', () => ({
default: mockUtils,
...mockFunctions
}));
const utils = (await import('utility-belt')).default;
const { debounce, deepClone } = await import('utility-belt');
// Test string utilities
expect(utils.string.capitalize('hello')).toBe('Hello');
expect(utils.string.kebabCase('Hello World')).toBe('hello-world');
// Test array utilities
const chunks = utils.array.chunk([1, 2, 3, 4, 5], 2);
expect(chunks).toEqual([[1, 2], [3, 4], [5]]);
const unique = utils.array.unique([1, 2, 2, 3, 3, 3]);
expect(unique).toEqual([1, 2, 3]);
// Test object utilities
const obj = { a: 1, b: 2, c: 3 };
const picked = utils.object.pick(obj, ['a', 'c']);
expect(picked).toEqual({ a: 1, c: 3 });
// Test function utilities
const originalFn = jest.fn();
const debouncedFn = debounce(originalFn, 100);
debouncedFn();
debouncedFn();
debouncedFn();
expect(originalFn).not.toHaveBeenCalled();
// Test deep clone
const original = { nested: { value: 42 } };
const cloned = deepClone(original);
cloned.nested.value = 100;
expect(original.nested.value).toBe(42);
expect(cloned.nested.value).toBe(100);
});
it('should handle CommonJS style exports', async () => {
// Mock logger library with CommonJS export
const mockLogger = {
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
child: jest.fn(() => mockLogger)
};
const mockCreateLogger = jest.fn(() => mockLogger);
jest.doMock('logger-lib', () => mockCreateLogger);
const createLogger = (await import('logger-lib')).default;
const logger = createLogger('test', {
level: 'info',
format: 'json',
output: 'console'
});
expect(mockCreateLogger).toHaveBeenCalledWith('test', {
level: 'info',
format: 'json',
output: 'console'
});
logger.info('Test message');
expect(logger.info).toHaveBeenCalledWith('Test message');
const childLogger = logger.child({ requestId: '123' });
expect(logger.child).toHaveBeenCalledWith({ requestId: '123' });
});
});
describe('Wildcard Module Testing', () => {
it('should handle JSON imports', async () => {
// Mock JSON file import
const mockConfig = { apiUrl: 'https://api.example.com', version: '1.0.0' };
jest.doMock('./config.json', () => mockConfig, { virtual: true });
const config = (await import('./config.json')).default;
expect(config).toEqual(mockConfig);
expect(config.apiUrl).toBe('https://api.example.com');
expect(config.version).toBe('1.0.0');
});
it('should handle CSS module imports', async () => {
// Mock CSS module import
const mockStyles = {
container: 'container_abc123',
button: 'button_def456',
active: 'active_ghi789'
};
jest.doMock('./component.css', () => ({ default: mockStyles }), { virtual: true });
const styles = (await import('./component.css')).default;
expect(styles).toEqual(mockStyles);
expect(typeof styles.container).toBe('string');
expect(styles.container).toMatch(/^container_/);
});
it('should handle asset imports', async () => {
// Mock asset imports
const mockImageSrc = '/static/media/hero.abc123.png';
const mockSvgContent = '<svg>...</svg>';
jest.doMock('./hero.png', () => ({ default: mockImageSrc }), { virtual: true });
jest.doMock('./logo.svg', () => ({ default: mockSvgContent }), { virtual: true });
const imageSrc = (await import('./hero.png')).default;
const svgContent = (await import('./logo.svg')).default;
expect(typeof imageSrc).toBe('string');
expect(imageSrc).toBe(mockImageSrc);
expect(typeof svgContent).toBe('string');
expect(svgContent).toBe(mockSvgContent);
});
});
describe('Environment-Specific Module Testing', () => {
it('should handle Node.js specific modules', async () => {
// Skip in browser environment
if (typeof window !== 'undefined') {
return;
}
// Mock Node.js specific module
const mockWatcher = {
close: jest.fn(),
add: jest.fn(),
remove: jest.fn(),
on: jest.fn(),
emit: jest.fn()
};
const mockProcessManager = {
spawn: jest.fn(),
exec: jest.fn(),
kill: jest.fn(),
list: jest.fn()
};
jest.doMock('node-specific-lib', () => ({
watch: jest.fn(() => mockWatcher),
processes: mockProcessManager,
isNode: () => true
}));
const { watch, processes, isNode } = await import('node-specific-lib');
expect(isNode()).toBe(true);
const watcher = watch('/path/to/watch', { recursive: true });
expect(watcher).toBe(mockWatcher);
expect(processes.spawn).toBeDefined();
expect(processes.exec).toBeDefined();
});
it('should handle browser specific modules', async () => {
// Mock browser environment
Object.defineProperty(global, 'window', {
value: {
navigator: { userAgent: 'Test Browser' },
location: { href: 'http://localhost' }
},
writable: true
});
// Mock browser specific module
const mockGeolocation = {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
clearWatch: jest.fn()
};
const mockStorage = {
local: {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn()
},
session: {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn()
},
cookie: {
get: jest.fn(),
set: jest.fn(),
remove: jest.fn(),
clear: jest.fn()
}
};
jest.doMock('browser-specific-lib', () => ({
getBrowserInfo: () => ({ name: 'Test', version: '1.0', engine: 'Test', os: 'Test' }),
geolocation: mockGeolocation,
storage: mockStorage,
notifications: {
request: jest.fn(),
show: jest.fn(),
isSupported: () => true
},
isBrowser: () => true
}));
const { getBrowserInfo, geolocation, storage, isBrowser } = await import('browser-specific-lib');
expect(isBrowser()).toBe(true);
const browserInfo = getBrowserInfo();
expect(browserInfo.name).toBe('Test');
expect(geolocation.getCurrentPosition).toBeDefined();
expect(storage.local.setItem).toBeDefined();
// Cleanup
delete (global as any).window;
});
});
describe('Plugin System Testing', () => {
it('should handle plugin-based module systems', async () => {
// Mock plugin system
const mockApp = {
plugins: {
register: jest.fn(),
unregister: jest.fn(),
get: jest.fn(),
list: jest.fn(),
isRegistered: jest.fn()
},
use: jest.fn(),
boot: jest.fn(),
shutdown: jest.fn()
};
jest.doMock('plugin-system', () => ({
createApp: () => mockApp
}));
const { createApp } = await import('plugin-system');
const app = createApp();
expect(app.plugins.register).toBeDefined();
expect(app.use).toBeDefined();
// Test plugin registration
const mockPlugin = {
name: 'test-plugin',
version: '1.0.0',
install: jest.fn()
};
await app.use(mockPlugin, { option: 'value' });
expect(app.use).toHaveBeenCalledWith(mockPlugin, { option: 'value' });
});
});
describe('Type Safety Validation', () => {
it('should enforce correct parameter types', () => {
// This test validates that TypeScript compilation would catch type errors
// In a real test environment, these would be compile-time checks
interface TestInterface {
stringProp: string;
numberProp: number;
booleanProp: boolean;
optionalProp?: string;
}
const createTestObject = (data: TestInterface): TestInterface => data;
// Valid usage
const validObject = createTestObject({
stringProp: 'test',
numberProp: 42,
booleanProp: true
});
expect(validObject.stringProp).toBe('test');
expect(validObject.numberProp).toBe(42);
expect(validObject.booleanProp).toBe(true);
// These would cause TypeScript compilation errors:
// createTestObject({ stringProp: 123 }); // Error: Type 'number' is not assignable to type 'string'
// createTestObject({ stringProp: 'test' }); // Error: Property 'numberProp' is missing
});
it('should handle generic types correctly', () => {
interface GenericResponse<T> {
data: T;
status: number;
message: string;
}
const createResponse = <T>(data: T, status: number = 200): GenericResponse<T> => ({
data,
status,
message: 'Success'
});
// Test with different types
const stringResponse = createResponse('Hello, World!');
expect(stringResponse.data).toBe('Hello, World!');
const numberResponse = createResponse(42);
expect(numberResponse.data).toBe(42);
const objectResponse = createResponse({ id: 1, name: 'Test' });
expect(objectResponse.data.id).toBe(1);
expect(objectResponse.data.name).toBe('Test');
const arrayResponse = createResponse([1, 2, 3]);
expect(arrayResponse.data).toEqual([1, 2, 3]);
});
});
describe('Module Resolution and Dependencies', () => {
afterEach(() => {
jest.resetModules();
});
it('should handle module dependencies correctly', async () => {
// Mock a module that depends on another module
jest.doMock('dependency-module', () => ({
utils: {
format: (str: string) => str.toUpperCase()
}
}));
jest.doMock('main-module', () => {
const dep = require('dependency-module');
return {
process: (input: string) => dep.utils.format(input)
};
});
const { process } = await import('main-module');
const result = process('hello world');
expect(result).toBe('HELLO WORLD');
});
it('should handle circular dependencies gracefully', async () => {
// Mock circular dependency scenario
jest.doMock('module-a', () => {
const moduleB = require('module-b');
return {
name: 'A',
callB: () => moduleB.name
};
});
jest.doMock('module-b', () => {
const moduleA = require('module-a');
return {
name: 'B',
callA: () => moduleA?.name || 'A'
};
});
const moduleA = await import('module-a');
const moduleB = await import('module-b');
expect(moduleA.name).toBe('A');
expect(moduleB.name).toBe('B');
expect(moduleB.callA()).toBe('A');
});
});
});
// Performance testing for ambient modules
describe('Ambient Module Performance', () => {
it('should have minimal overhead for type checking', () => {
// Test that ambient module declarations don't impact runtime performance
const iterations = 10000;
interface LargeInterface {
prop1: string;
prop2: number;
prop3: boolean;
prop4: Date;
prop5: any[];
// ... many more properties
}
const createLargeObject = (id: number): LargeInterface => ({
prop1: `string-${id}`,
prop2: id,
prop3: id % 2 === 0,
prop4: new Date(),
prop5: [1, 2, 3]
});
const start = performance.now();
for (let i = 0; i < iterations; i++) {
const obj = createLargeObject(i);
// Use the object to prevent optimization
expect(obj.prop1).toBeDefined();
}
const end = performance.now();
const duration = end - start;
// Should complete quickly (type checking is compile-time)
expect(duration).toBeLessThan(1000);
});
});
π― Conclusion
Congratulations! Youβve now mastered the comprehensive art of ambient modules in TypeScript! π
Throughout this tutorial, youβve learned how to:
- Master ambient module declarations for external JavaScript libraries and packages
- Create comprehensive type definitions that make any JavaScript library feel like first-class TypeScript
- Build sophisticated management systems for tracking and maintaining ambient module declarations at scale
- Handle complex scenarios including environment-specific modules, plugin systems, and wildcard patterns
- Implement robust testing strategies that ensure your ambient modules work correctly across different environments
Ambient modules are your bridge between the TypeScript world and the vast JavaScript ecosystem. They allow you to bring type safety and excellent developer experience to any external library, while maintaining flexibility and compatibility. The key is to create accurate, comprehensive declarations that reflect the true nature of the underlying JavaScript code.
Remember: ambient modules are about translation and representation, not modification. Your declarations should faithfully represent the external libraryβs API while providing the best possible TypeScript experience. With the management system and testing strategies youβve learned, you can confidently create and maintain ambient modules that make the entire JavaScript ecosystem feel native to TypeScript.
Keep practicing these patterns, and youβll find that ambient modules become an invaluable tool for creating seamless integrations between TypeScript and any JavaScript library, making your development experience smooth and type-safe! π