import { createExpressApp, createFastifyApp, isHttpApp, implementsHttpApp, HttpApp } from '../src/infra/http/http-app'; /** * Interface Checking Example * * This example demonstrates different ways to check if an object * implements the HttpApp interface at runtime. */ async function interfaceCheckingExample() { console.log('🔍 Interface Checking Example'); console.log('============================\n'); // Create different app instances const expressApp = createExpressApp(); const fastifyApp = createFastifyApp(); const plainObject = { someProperty: 'value' }; const nullValue = null; const undefinedValue = undefined; // Test objects array const testObjects = [ { name: 'ExpressApp', obj: expressApp }, { name: 'FastifyApp', obj: fastifyApp }, { name: 'PlainObject', obj: plainObject }, { name: 'NullValue', obj: nullValue }, { name: 'UndefinedValue', obj: undefinedValue } ]; console.log('1. Brand Property Check (isHttpApp)'); console.log('-----------------------------------'); testObjects.forEach(({ name, obj }) => { const isApp = isHttpApp(obj); console.log(`${name}: ${isApp ? '✅' : '❌'} (${typeof obj})`); if (isApp) { // TypeScript knows this is HttpApp console.log(` - Plugins: ${obj.listPlugins().length}`); console.log(` - Started: ${obj.isApplicationStarted()}`); } }); console.log('\n2. Duck Typing Check (implementsHttpApp)'); console.log('------------------------------------------'); testObjects.forEach(({ name, obj }) => { const implementsApp = implementsHttpApp(obj); console.log(`${name}: ${implementsApp ? '✅' : '❌'} (${typeof obj})`); if (implementsApp) { // TypeScript knows this implements HttpApp interface console.log(` - Has start method: ${typeof obj.start === 'function'}`); console.log(` - Has stop method: ${typeof obj.stop === 'function'}`); } }); console.log('\n3. Manual Property Checking'); console.log('----------------------------'); testObjects.forEach(({ name, obj }) => { const hasRequiredMethods = checkRequiredMethods(obj); console.log(`${name}: ${hasRequiredMethods ? '✅' : '❌'}`); if (hasRequiredMethods) { console.log(` - All required methods present`); } else { const missingMethods = getMissingMethods(obj); console.log(` - Missing methods: ${missingMethods.join(', ')}`); } }); console.log('\n4. Practical Usage Example'); console.log('---------------------------'); await demonstratePracticalUsage(); } // Manual method checking function checkRequiredMethods(obj: any): boolean { const requiredMethods = [ 'start', 'stop', 'getApp', 'getServer', 'getRouteRegistry', 'getMiddlewareRegistry', 'getContainer', 'register', 'usePlugin', 'getPlugin', 'listPlugins' ]; return requiredMethods.every(method => typeof obj?.[method] === 'function'); } function getMissingMethods(obj: any): string[] { const requiredMethods = [ 'start', 'stop', 'getApp', 'getServer', 'getRouteRegistry', 'getMiddlewareRegistry', 'getContainer', 'register', 'usePlugin', 'getPlugin', 'listPlugins' ]; return requiredMethods.filter(method => typeof obj?.[method] !== 'function'); } // Practical usage demonstration async function demonstratePracticalUsage() { console.log('Practical Usage:'); // Function that accepts any object and checks if it's HttpApp async function startAppIfHttpApp(obj: any): Promise { if (isHttpApp(obj)) { console.log('✅ Object is HttpApp, starting server...'); try { await obj.start(3000); console.log('✅ Server started successfully'); // Stop after a short delay setTimeout(async () => { await obj.stop(); console.log('✅ Server stopped'); }, 2000); return true; } catch (error) { console.error('❌ Failed to start server:', error); return false; } } else { console.log('❌ Object is not HttpApp, cannot start server'); return false; } } // Test with different objects const expressApp = createExpressApp(); const plainObject = { name: 'not an app' }; await startAppIfHttpApp(expressApp); await startAppIfHttpApp(plainObject); } // Advanced type checking with generics function processHttpApp(obj: any): obj is HttpApp { return isHttpApp(obj); } // Factory function with type checking function createAppSafely(type: 'express' | 'fastify'): HttpApp | null { let app: any; try { if (type === 'express') { app = createExpressApp(); } else if (type === 'fastify') { app = createFastifyApp(); } else { throw new Error(`Unknown app type: ${type}`); } // Verify it's actually an HttpApp if (!isHttpApp(app)) { throw new Error(`Created object does not implement HttpApp interface`); } return app; } catch (error) { console.error('Failed to create app:', error); return null; } } // Error handling with type checking async function safeAppOperation(obj: any, operation: 'start' | 'stop'): Promise { if (!isHttpApp(obj)) { console.error('Object does not implement HttpApp interface'); return false; } try { if (operation === 'start') { await obj.start(3000); console.log('App started successfully'); } else if (operation === 'stop') { await obj.stop(); console.log('App stopped successfully'); } return true; } catch (error) { console.error(`Failed to ${operation} app:`, error); return false; } } // Plugin management with type checking function addPluginSafely(app: any, pluginName: string, plugin: any): boolean { if (!isHttpApp(app)) { console.error('Cannot add plugin: object is not HttpApp'); return false; } try { app.usePlugin(plugin); console.log(`Plugin '${pluginName}' added successfully`); return true; } catch (error) { console.error(`Failed to add plugin '${pluginName}':`, error); return false; } } // Export utility functions export { isHttpApp, implementsHttpApp, checkRequiredMethods, getMissingMethods, processHttpApp, createAppSafely, safeAppOperation, addPluginSafely }; // Run the example if (require.main === module) { interfaceCheckingExample().catch(console.error); } export default interfaceCheckingExample;