Advanced Patterns and Enterprise Features

1. Dependency Injection and IoC Container Typing

Library/Pattern Approach Type Safety Use Case
InversifyJS Decorator-based DI container - @injectable, @inject Full type inference, constructor injection Enterprise apps, testable architecture
TSyringe Lightweight DI - Microsoft library Decorator metadata, automatic resolution Node.js services, Clean Architecture
TypeDI Dependency injection for TypeScript/JavaScript Service tokens, type-safe containers TypeORM integration, modular apps
Manual DI Pattern Constructor injection without container Explicit types, no magic Simple apps, avoid framework lock-in
Factory Pattern Type-safe factories with generics Return type inference Object creation, polymorphism
Service Locator Central registry for dependencies Type-safe get methods Legacy integration, runtime resolution

Example: InversifyJS dependency injection

// Install: npm i inversify reflect-metadata

// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

// types.ts - Define service identifiers
export const TYPES = {
  Database: Symbol.for('Database'),
  Logger: Symbol.for('Logger'),
  UserService: Symbol.for('UserService')
};

// interfaces.ts
export interface ILogger {
  log(message: string): void;
}

export interface IDatabase {
  query(sql: string): Promise<any>;
}

export interface IUserService {
  getUser(id: string): Promise<User>;
}

// implementations.ts
import { injectable, inject } from 'inversify';
import 'reflect-metadata';

@injectable()
export class ConsoleLogger implements ILogger {
  log(message: string): void {
    console.log(`[LOG] ${message}`);
  }
}

@injectable()
export class PostgresDatabase implements IDatabase {
  async query(sql: string): Promise<any> {
    // Database implementation
    return [];
  }
}

@injectable()
export class UserService implements IUserService {
  constructor(
    @inject(TYPES.Database) private database: IDatabase,
    @inject(TYPES.Logger) private logger: ILogger
  ) {}

  async getUser(id: string): Promise<User> {
    this.logger.log(`Fetching user ${id}`);
    const result = await this.database.query(
      `SELECT * FROM users WHERE id = '${id}'`
    );
    return result[0];
  }
}

// container.ts - Configure DI container
import { Container } from 'inversify';

const container = new Container();

container.bind<ILogger>(TYPES.Logger).to(ConsoleLogger);
container.bind<IDatabase>(TYPES.Database).to(PostgresDatabase);
container.bind<IUserService>(TYPES.UserService).to(UserService);

export { container };

// Usage
import { container } from './container';

const userService = container.get<IUserService>(TYPES.UserService);
const user = await userService.getUser('123');  // Fully typed!

// Testing - easy to mock dependencies
const mockLogger: ILogger = { log: jest.fn() };
const mockDatabase: IDatabase = { query: jest.fn() };

const testContainer = new Container();
testContainer.bind<ILogger>(TYPES.Logger).toConstantValue(mockLogger);
testContainer.bind<IDatabase>(TYPES.Database).toConstantValue(mockDatabase);

Example: Manual DI pattern (no framework)

// Simple, explicit dependency injection

// Services
interface Logger {
  log(message: string): void;
}

interface Database {
  query<T>(sql: string): Promise<T[]>;
}

class ConsoleLogger implements Logger {
  log(message: string): void {
    console.log(message);
  }
}

class PostgresDB implements Database {
  async query<T>(sql: string): Promise<T[]> {
    // Implementation
    return [] as T[];
  }
}

// Service with constructor injection
class UserService {
  constructor(
    private readonly db: Database,
    private readonly logger: Logger
  ) {}

  async getUser(id: string): Promise<User> {
    this.logger.log(`Fetching user ${id}`);
    const [user] = await this.db.query<User>(
      `SELECT * FROM users WHERE id = $1`
    );
    return user;
  }
}

// Manual wiring (composition root)
function createServices() {
  const logger = new ConsoleLogger();
  const database = new PostgresDB();
  const userService = new UserService(database, logger);
  
  return {
    logger,
    database,
    userService
  };
}

// Usage
const services = createServices();
const user = await services.userService.getUser('123');

// Testing - inject mocks
const mockDB: Database = {
  query: jest.fn().mockResolvedValue([{ id: '123', name: 'Alice' }])
};
const mockLogger: Logger = { log: jest.fn() };
const testService = new UserService(mockDB, mockLogger);

// Type-safe factory pattern
type ServiceFactory<T> = () => T;

class ServiceContainer {
  private factories = new Map<string, ServiceFactory<any>>();
  private instances = new Map<string, any>();

  register<T>(name: string, factory: ServiceFactory<T>): void {
    this.factories.set(name, factory);
  }

  get<T>(name: string): T {
    if (!this.instances.has(name)) {
      const factory = this.factories.get(name);
      if (!factory) throw new Error(`Service ${name} not registered`);
      this.instances.set(name, factory());
    }
    return this.instances.get(name) as T;
  }
}

// Usage
const container = new ServiceContainer();
container.register<Logger>('logger', () => new ConsoleLogger());
container.register<Database>('database', () => new PostgresDB());
container.register<UserService>(
  'userService',
  () => new UserService(
    container.get<Database>('database'),
    container.get<Logger>('logger')
  )
);

const service = container.get<UserService>('userService');

2. Plugin Architecture and Type-safe APIs

Pattern Implementation Type Safety Benefit
Plugin Interface Define contract for all plugins Enforce plugin structure Consistent plugin API
Hook System Type-safe event hooks with generics Typed hook parameters and returns Extensibility without modification
Plugin Registry Type-safe plugin registration and discovery Infer plugin types automatically Dynamic plugin loading
Middleware Pattern Composable middleware chain Type-safe context passing Request/response transformation
Extension Points Predefined places for extension Typed extension contracts Open-closed principle
Builder Pattern Fluent API with type constraints Type-safe method chaining Progressive configuration

Example: Type-safe plugin system

// Define plugin interface
interface Plugin<TConfig = unknown> {
  name: string;
  version: string;
  config?: TConfig;
  
  // Lifecycle hooks
  init?(context: PluginContext): void | Promise<void>;
  beforeRequest?(req: Request): Request | Promise<Request>;
  afterResponse?(res: Response): Response | Promise<Response>;
  destroy?(): void | Promise<void>;
}

// Plugin context with typed services
interface PluginContext {
  logger: Logger;
  config: AppConfig;
  registerHook<T>(name: string, handler: HookHandler<T>): void;
}

// Hook system with generics
type HookHandler<T> = (data: T) => T | Promise<T>;

class HookManager {
  private hooks = new Map<string, HookHandler<any>[]>();

  register<T>(name: string, handler: HookHandler<T>): void {
    const handlers = this.hooks.get(name) ?? [];
    handlers.push(handler);
    this.hooks.set(name, handlers);
  }

  async execute<T>(name: string, data: T): Promise<T> {
    const handlers = this.hooks.get(name) ?? [];
    let result = data;
    for (const handler of handlers) {
      result = await handler(result);
    }
    return result;
  }
}

// Plugin registry with type inference
class PluginRegistry {
  private plugins = new Map<string, Plugin>();

  register<T extends Plugin>(plugin: T): void {
    this.plugins.set(plugin.name, plugin);
  }

  get<T extends Plugin>(name: string): T | undefined {
    return this.plugins.get(name) as T | undefined;
  }

  getAll(): Plugin[] {
    return Array.from(this.plugins.values());
  }
}

// Example plugins
interface LoggingPluginConfig {
  level: 'info' | 'debug' | 'error';
  format: 'json' | 'text';
}

class LoggingPlugin implements Plugin<LoggingPluginConfig> {
  name = 'logging';
  version = '1.0.0';
  
  constructor(public config: LoggingPluginConfig) {}

  init(context: PluginContext): void {
    context.logger.log(`Logging plugin initialized with level: ${this.config.level}`);
  }

  async beforeRequest(req: Request): Promise<Request> {
    console.log(`[${this.config.level}] Request: ${req.url}`);
    return req;
  }
}

interface CachePluginConfig {
  ttl: number;
  maxSize: number;
}

class CachePlugin implements Plugin<CachePluginConfig> {
  name = 'cache';
  version = '1.0.0';
  private cache = new Map<string, any>();

  constructor(public config: CachePluginConfig) {}

  async afterResponse(res: Response): Promise<Response> {
    // Cache logic
    return res;
  }
}

// Application with plugins
class Application {
  private registry = new PluginRegistry();
  private hooks = new HookManager();

  use<T extends Plugin>(plugin: T): this {
    this.registry.register(plugin);
    
    const context: PluginContext = {
      logger: console,
      config: {},
      registerHook: (name, handler) => this.hooks.register(name, handler)
    };

    plugin.init?.(context);
    return this;  // Fluent API
  }

  async handleRequest(req: Request): Promise<Response> {
    // Execute beforeRequest hooks
    const modifiedReq = await this.hooks.execute('beforeRequest', req);
    
    // Process request
    const response = await this.processRequest(modifiedReq);
    
    // Execute afterResponse hooks
    return this.hooks.execute('afterResponse', response);
  }

  private async processRequest(req: Request): Promise<Response> {
    // Implementation
    return new Response();
  }
}

// Usage - fully typed!
const app = new Application()
  .use(new LoggingPlugin({ level: 'debug', format: 'json' }))
  .use(new CachePlugin({ ttl: 3600, maxSize: 100 }));

await app.handleRequest(new Request('https://api.example.com'));

3. Schema Validation Integration (Zod, Joi)

Library Features Type Inference Use Case
Zod TypeScript-first, composable, no dependencies Infer types from schemas - z.infer<typeof schema> API validation, form validation, config parsing
Joi Mature, extensive validators, plugins Manual type definitions or joi-to-typescript Node.js APIs, configuration validation
Yup Similar to Joi, smaller bundle InferType<typeof schema> utility Form validation (React Hook Form, Formik)
io-ts Functional programming style, codec pattern Runtime + compile-time validation Functional codebases, API boundaries
class-validator Decorator-based validation Works with TypeScript classes NestJS, class-based DTOs
ArkType Ultra-fast, TypeScript syntax 1:1 TypeScript to runtime validation Performance-critical validation

Example: Zod schema validation

// Install: npm i zod
import { z } from 'zod';

// Define schema
const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().positive().optional(),
  role: z.enum(['admin', 'user', 'guest']),
  createdAt: z.date(),
  metadata: z.record(z.unknown()).optional()
});

// Infer TypeScript type from schema
type User = z.infer<typeof UserSchema>;
// Equivalent to:
// type User = {
//   id: string;
//   name: string;
//   email: string;
//   age?: number | undefined;
//   role: 'admin' | 'user' | 'guest';
//   createdAt: Date;
//   metadata?: Record<string, unknown> | undefined;
// }

// Validation
function createUser(data: unknown): User {
  // Parse and validate - throws on error
  return UserSchema.parse(data);
}

// Safe parsing - returns result object
function safeCreateUser(data: unknown): User | null {
  const result = UserSchema.safeParse(data);
  if (result.success) {
    return result.data;  // Typed as User
  } else {
    console.error(result.error.issues);
    return null;
  }
}

// Nested schemas
const AddressSchema = z.object({
  street: z.string(),
  city: z.string(),
  zipCode: z.string().regex(/^\d{5}$/),
  country: z.string().length(2)  // ISO country code
});

const UserWithAddressSchema = UserSchema.extend({
  address: AddressSchema,
  billingAddress: AddressSchema.optional()
});

type UserWithAddress = z.infer<typeof UserWithAddressSchema>;

// Array and union schemas
const UsersSchema = z.array(UserSchema);
type Users = z.infer<typeof UsersSchema>;  // User[]

const StringOrNumberSchema = z.union([z.string(), z.number()]);
type StringOrNumber = z.infer<typeof StringOrNumberSchema>;  // string | number

// Refinements and custom validation
const PasswordSchema = z.string()
  .min(8, 'Password must be at least 8 characters')
  .regex(/[A-Z]/, 'Password must contain uppercase letter')
  .regex(/[0-9]/, 'Password must contain number');

const ConfirmPasswordSchema = z.object({
  password: PasswordSchema,
  confirmPassword: z.string()
}).refine(
  (data) => data.password === data.confirmPassword,
  { message: 'Passwords must match', path: ['confirmPassword'] }
);

// Transform data
const DateStringSchema = z.string().transform((str) => new Date(str));
const trimmedString = z.string().transform((s) => s.trim());

// API endpoint with validation
import { Request, Response } from 'express';

const CreateUserRequestSchema = z.object({
  body: UserSchema.omit({ id: true, createdAt: true }),
  query: z.object({
    sendEmail: z.string().transform(s => s === 'true').optional()
  })
});

async function createUserHandler(req: Request, res: Response) {
  try {
    const { body, query } = CreateUserRequestSchema.parse({
      body: req.body,
      query: req.query
    });
    
    // body and query are fully typed!
    const user = await saveUser(body);
    
    if (query.sendEmail) {
      await sendWelcomeEmail(user.email);
    }
    
    res.json(user);
  } catch (error) {
    if (error instanceof z.ZodError) {
      res.status(400).json({ errors: error.issues });
    } else {
      res.status(500).json({ error: 'Internal server error' });
    }
  }
}

Example: Joi validation

// Install: npm i joi @types/joi
import Joi from 'joi';

// Define schema
const userSchema = Joi.object({
  id: Joi.string().uuid().required(),
  name: Joi.string().min(1).max(100).required(),
  email: Joi.string().email().required(),
  age: Joi.number().integer().positive().optional(),
  role: Joi.string().valid('admin', 'user', 'guest').required(),
  createdAt: Joi.date().required(),
  metadata: Joi.object().unknown(true).optional()
});

// Manual type definition (or use joi-to-typescript)
interface User {
  id: string;
  name: string;
  email: string;
  age?: number;
  role: 'admin' | 'user' | 'guest';
  createdAt: Date;
  metadata?: Record<string, unknown>;
}

// Validation
function validateUser(data: unknown): User {
  const { error, value } = userSchema.validate(data, {
    abortEarly: false,  // Return all errors
    stripUnknown: true  // Remove unknown properties
  });

  if (error) {
    throw new Error(`Validation failed: ${error.message}`);
  }

  return value as User;
}

// Express middleware for validation
function validate(schema: Joi.Schema) {
  return (req: Request, res: Response, next: Function) => {
    const { error, value } = schema.validate(req.body, {
      abortEarly: false
    });

    if (error) {
      const errors = error.details.map(d => ({
        field: d.path.join('.'),
        message: d.message
      }));
      return res.status(400).json({ errors });
    }

    req.body = value;  // Replace with validated data
    next();
  };
}

// Usage
app.post('/users', validate(userSchema), createUserHandler);

4. ORM Integration (Prisma, TypeORM) Type Safety

ORM Type Generation Query Builder Features
Prisma Generate types from schema - prisma generate Fluent API, full type inference Best-in-class types, migrations, Prisma Studio
TypeORM Decorators on entities - infer from classes Repository pattern, QueryBuilder Mature, Active Record/Data Mapper patterns
Drizzle ORM TypeScript-first, schema definition SQL-like builder with full types Lightweight, edge-compatible, serverless
Kysely Type-safe SQL query builder Composable queries with inference Raw SQL control with type safety
MikroORM Entity classes with decorators Unit of Work, Identity Map DDD patterns, complex relationships

Example: Prisma type-safe ORM

// Install: npm i @prisma/client
// Dev: npm i -D prisma

// Initialize Prisma
// npx prisma init

// schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String
  role      Role     @default(USER)
  posts     Post[]
  profile   Profile?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Post {
  id        String   @id @default(uuid())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String
  tags      Tag[]
  createdAt DateTime @default(now())
}

model Profile {
  id     String @id @default(uuid())
  bio    String
  userId String @unique
  user   User   @relation(fields: [userId], references: [id])
}

model Tag {
  id    String @id @default(uuid())
  name  String @unique
  posts Post[]
}

enum Role {
  USER
  ADMIN
  MODERATOR
}

// Generate Prisma Client
// npx prisma generate

// Usage - fully typed!
import { PrismaClient, Prisma } from '@prisma/client';

const prisma = new PrismaClient();

// Type-safe queries
async function getUser(id: string) {
  const user = await prisma.user.findUnique({
    where: { id },
    include: {
      posts: true,
      profile: true
    }
  });
  // user type is inferred: User & { posts: Post[], profile: Profile | null }
  return user;
}

// Type-safe create
async function createUser(data: Prisma.UserCreateInput) {
  return prisma.user.create({
    data: {
      email: data.email,
      name: data.name,
      profile: {
        create: {
          bio: 'New user'
        }
      }
    }
  });
}

// Type-safe where conditions
async function findUsers(filter: Prisma.UserWhereInput) {
  return prisma.user.findMany({
    where: filter,
    orderBy: { createdAt: 'desc' }
  });
}

// Usage
const admins = await findUsers({ role: 'ADMIN' });  // Fully typed!

// Type-safe updates
await prisma.user.update({
  where: { id: '123' },
  data: {
    name: 'New Name',
    posts: {
      create: {
        title: 'New Post',
        content: 'Content here'
      }
    }
  }
});

// Aggregations with types
const stats = await prisma.post.aggregate({
  _count: { id: true },
  _avg: { authorId: false },
  where: { published: true }
});
// stats is fully typed

// Transactions
await prisma.$transaction([
  prisma.user.create({ data: { email: 'user@example.com', name: 'User' } }),
  prisma.post.create({ data: { title: 'Post', authorId: '...' } })
]);

// Raw queries with types
const users = await prisma.$queryRaw<User[]>`
  SELECT * FROM "User" WHERE role = ${Prisma.Role.ADMIN}
`;

Example: TypeORM entities

// Install: npm i typeorm reflect-metadata
// Database driver: npm i pg (for PostgreSQL)

// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

// entities/User.ts
import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  OneToMany,
  OneToOne
} from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn('uuid')
  id!: string;

  @Column({ unique: true })
  email!: string;

  @Column()
  name!: string;

  @Column({ type: 'enum', enum: ['USER', 'ADMIN', 'MODERATOR'], default: 'USER' })
  role!: 'USER' | 'ADMIN' | 'MODERATOR';

  @OneToMany(() => Post, post => post.author)
  posts!: Post[];

  @OneToOne(() => Profile, profile => profile.user)
  profile?: Profile;

  @CreateDateColumn()
  createdAt!: Date;

  @UpdateDateColumn()
  updatedAt!: Date;
}

// entities/Post.ts
@Entity()
export class Post {
  @PrimaryGeneratedColumn('uuid')
  id!: string;

  @Column()
  title!: string;

  @Column({ type: 'text', nullable: true })
  content?: string;

  @Column({ default: false })
  published!: boolean;

  @ManyToOne(() => User, user => user.posts)
  author!: User;

  @CreateDateColumn()
  createdAt!: Date;
}

// data-source.ts
import { DataSource } from 'typeorm';

export const AppDataSource = new DataSource({
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  username: 'user',
  password: 'password',
  database: 'mydb',
  entities: [User, Post, Profile],
  synchronize: true,  // Don't use in production!
  logging: true
});

// Usage
await AppDataSource.initialize();

const userRepository = AppDataSource.getRepository(User);

// Type-safe queries
const user = await userRepository.findOne({
  where: { email: 'user@example.com' },
  relations: ['posts', 'profile']
});

// QueryBuilder with types
const users = await userRepository
  .createQueryBuilder('user')
  .leftJoinAndSelect('user.posts', 'post')
  .where('user.role = :role', { role: 'ADMIN' })
  .andWhere('post.published = :published', { published: true })
  .getMany();

// Type-safe create
const newUser = userRepository.create({
  email: 'new@example.com',
  name: 'New User',
  role: 'USER'
});
await userRepository.save(newUser);

// Transactions
await AppDataSource.transaction(async (manager) => {
  const user = manager.create(User, { email: 'user@example.com', name: 'User' });
  await manager.save(user);
  
  const post = manager.create(Post, { title: 'Post', author: user });
  await manager.save(post);
});

5. GraphQL Code Generation and Type Safety

Tool Purpose Output Use Case
GraphQL Code Generator Generate TypeScript from GraphQL schema/operations Types, hooks, resolvers, operations Full-stack GraphQL apps
Apollo Client GraphQL client with TypeScript support useQuery, useMutation hooks with types React/Vue GraphQL frontends
TypeGraphQL Create GraphQL schema using TypeScript classes Schema-first from decorators TypeScript-first GraphQL APIs
Pothos GraphQL Code-first GraphQL schema builder Type-safe schema construction Type-safe server schema definition
gql-tag Parse GraphQL queries Tagged template literals Client-side query definition
GraphQL ESLint Lint GraphQL operations Catch errors at compile time Query validation

Example: GraphQL Code Generator

// Install: npm i -D @graphql-codegen/cli @graphql-codegen/typescript
// npm i -D @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo

// schema.graphql
type User {
  id: ID!
  email: String!
  name: String!
  role: Role!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  content: String
  published: Boolean!
  author: User!
}

enum Role {
  USER
  ADMIN
  MODERATOR
}

type Query {
  user(id: ID!): User
  users(role: Role): [User!]!
  post(id: ID!): Post
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!
}

input CreateUserInput {
  email: String!
  name: String!
  role: Role = USER
}

input UpdateUserInput {
  email: String
  name: String
  role: Role
}

// codegen.yml
overwrite: true
schema: "http://localhost:4000/graphql"
documents: "src/**/*.graphql"
generates:
  src/generated/graphql.ts:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-apollo"
    config:
      withHooks: true
      withComponent: false

// queries.graphql
query GetUser($id: ID!) {
  user(id: $id) {
    id
    email
    name
    role
    posts {
      id
      title
      published
    }
  }
}

query GetUsers($role: Role) {
  users(role: $role) {
    id
    email
    name
    role
  }
}

mutation CreateUser($input: CreateUserInput!) {
  createUser(input: $input) {
    id
    email
    name
    role
  }
}

// Generate types
// npx graphql-codegen

// Usage - generated hooks are fully typed!
import { useGetUserQuery, useCreateUserMutation } from './generated/graphql';

function UserProfile({ userId }: { userId: string }) {
  const { data, loading, error } = useGetUserQuery({
    variables: { id: userId }
  });

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  // data.user is fully typed!
  return (
    <div>
      <h1>{data?.user?.name}</h1>
      <p>{data?.user?.email}</p>
      <ul>
        {data?.user?.posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

function CreateUserForm() {
  const [createUser, { loading, error }] = useCreateUserMutation();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    await createUser({
      variables: {
        input: {
          email: 'new@example.com',
          name: 'New User',
          role: 'USER'  // Typed as Role enum!
        }
      }
    });
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

6. Microservice Communication and API Contracts

Pattern/Tool Implementation Type Safety Use Case
tRPC End-to-end type-safe APIs without code generation Infer client types from server TypeScript monorepos, full-stack apps
OpenAPI/Swagger API specification with TypeScript generation Generate types from OpenAPI spec REST APIs, polyglot services
gRPC Protocol Buffers with TypeScript Generate from .proto files High-performance microservices
Message Queue Type-safe message schemas (Zod/JSON Schema) Validate messages at runtime Event-driven architecture
API Client Generation Generate SDK from API definition Auto-generated type-safe client External API integration
Contract Testing Pact, MSW for API contracts Type-safe mock servers Consumer-driven contracts

Example: tRPC end-to-end type safety

// Install: npm i @trpc/server @trpc/client @trpc/react-query

// server/router.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';

const t = initTRPC.create();

// Define router
export const appRouter = t.router({
  // Query
  getUser: t.procedure
    .input(z.object({ id: z.string() }))
    .query(async ({ input }) => {
      // Fetch user from database
      return {
        id: input.id,
        name: 'Alice',
        email: 'alice@example.com'
      };
    }),

  // Query with transformed output
  getUsers: t.procedure
    .input(z.object({
      role: z.enum(['admin', 'user']).optional()
    }))
    .query(async ({ input }) => {
      // Return array of users
      return [];
    }),

  // Mutation
  createUser: t.procedure
    .input(z.object({
      name: z.string().min(1),
      email: z.string().email(),
      role: z.enum(['admin', 'user']).default('user')
    }))
    .mutation(async ({ input }) => {
      // Create user in database
      return {
        id: '123',
        ...input
      };
    }),

  // Nested routers
  posts: t.router({
    list: t.procedure.query(() => []),
    get: t.procedure
      .input(z.object({ id: z.string() }))
      .query(({ input }) => null)
  })
});

export type AppRouter = typeof appRouter;

// server/index.ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';

createHTTPServer({
  router: appRouter,
  createContext: () => ({})
}).listen(3000);

// client/trpc.ts
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '../server/router';

export const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3000'
    })
  ]
});

// Usage - fully typed!
const user = await trpc.getUser.query({ id: '123' });
// user is typed based on server return type!

const newUser = await trpc.createUser.mutate({
  name: 'Bob',
  email: 'bob@example.com',
  role: 'admin'
});
// Input is validated with Zod, output is typed!

// React integration
import { createTRPCReact } from '@trpc/react-query';

export const trpcReact = createTRPCReact<AppRouter>();

// In component
function UserProfile({ userId }: { userId: string }) {
  const { data, isLoading } = trpcReact.getUser.useQuery({ id: userId });
  
  // data is fully typed!
  return <div>{data?.name}</div>;
}

// Mutation
function CreateUser() {
  const mutation = trpcReact.createUser.useMutation();
  
  const handleSubmit = () => {
    mutation.mutate({
      name: 'Charlie',
      email: 'charlie@example.com'
    });
  };
  
  return <button onClick={handleSubmit}>Create</button>;
}

Example: OpenAPI type generation

// openapi.yaml
openapi: 3.0.0
info:
  title: User API
  version: 1.0.0

paths:
  /users/{id}:
    get:
      operationId: getUser
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: User found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

  /users:
    post:
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

components:
  schemas:
    User:
      type: object
      required:
        - id
        - email
        - name
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        name:
          type: string
        role:
          type: string
          enum: [user, admin]

    CreateUserRequest:
      type: object
      required:
        - email
        - name
      properties:
        email:
          type: string
          format: email
        name:
          type: string
        role:
          type: string
          enum: [user, admin]
          default: user

// Install: npm i -D openapi-typescript
// Generate types: npx openapi-typescript openapi.yaml -o src/api.d.ts

// api.d.ts (generated)
export interface paths {
  '/users/{id}': {
    get: operations['getUser'];
  };
  '/users': {
    post: operations['createUser'];
  };
}

export interface components {
  schemas: {
    User: {
      id: string;
      email: string;
      name: string;
      role?: 'user' | 'admin';
    };
    CreateUserRequest: {
      email: string;
      name: string;
      role?: 'user' | 'admin';
    };
  };
}

export interface operations {
  getUser: {
    parameters: { path: { id: string } };
    responses: { 200: { content: { 'application/json': components['schemas']['User'] } } };
  };
  createUser: {
    requestBody: { content: { 'application/json': components['schemas']['CreateUserRequest'] } };
    responses: { 201: { content: { 'application/json': components['schemas']['User'] } } };
  };
}

// Usage with type-safe client
import type { paths } from './api';
import createClient from 'openapi-fetch';

const client = createClient<paths>({ baseUrl: 'https://api.example.com' });

// Fully typed requests and responses!
const { data, error } = await client.GET('/users/{id}', {
  params: { path: { id: '123' } }
});
// data is typed as User

const { data: newUser } = await client.POST('/users', {
  body: {
    email: 'user@example.com',
    name: 'User',
    role: 'admin'
  }
});
// body and data are fully typed!
Note: Enterprise patterns best practices:
  • Dependency Injection - Use InversifyJS or TSyringe for complex apps, manual DI for simplicity
  • Plugins - Define plugin interfaces, type-safe hook system, plugin registry with generics
  • Validation - Use Zod for TypeScript-first validation, infer types from schemas
  • ORMs - Prisma offers best TypeScript experience, TypeORM for mature ecosystem
  • GraphQL - Use GraphQL Code Generator for full type safety, tRPC for TypeScript-only stacks
  • Microservices - tRPC for monorepos, OpenAPI for polyglot, gRPC for performance

Advanced Patterns and Enterprise Features Summary

  • Dependency Injection - InversifyJS/TSyringe for complex DI, manual injection for simple cases
  • Plugin Architecture - Type-safe plugin interfaces, hook systems, registries with generics
  • Schema Validation - Zod for TypeScript-first validation with type inference from schemas
  • ORMs - Prisma (best types), TypeORM (mature), Drizzle (lightweight), all with full type safety
  • GraphQL - Code generation from schema/queries, TypeGraphQL for code-first, full type safety
  • Microservices - tRPC for end-to-end types, OpenAPI generation, gRPC with Protocol Buffers