Skip to content

Examples

This section provides real-world examples of using fluent-gen-ts in various scenarios.

Basic Examples

Simple User Builder

Input Type:

typescript
// types/user.ts
export interface User {
  id: string;
  username: string;
  email: string;
  firstName: string;
  lastName: string;
  age: number;
  isActive: boolean;
  role: 'admin' | 'user' | 'guest';
  createdAt: Date;
  lastLoginAt?: Date;
}

Generated Builder Usage:

typescript
import { user } from './builders/user.builder.js';

// Create a basic user
const basicUser = user()
  .withId('user-123')
  .withUsername('johndoe')
  .withEmail('john@example.com')
  .withFirstName('John')
  .withLastName('Doe')
  .withAge(30)
  .withIsActive(true)
  .withRole('user')
  .withCreatedAt(new Date())
  .build();

// Create an admin user with conditional logic
const adminUser = user()
  .withId('admin-456')
  .withUsername('admin')
  .withEmail('admin@company.com')
  .withFirstName('Admin')
  .withLastName('User')
  .withAge(35)
  .withRole('admin')
  .withIsActive(true)
  .withCreatedAt(new Date())
  .if(u => u.peek('role') === 'admin', 'lastLoginAt', new Date())
  .build();

// Using with partial initial data
const partialUser = user({
  id: 'user-789',
  username: 'existing',
  createdAt: new Date('2023-01-01'),
})
  .withEmail('updated@example.com')
  .withFirstName('Updated')
  .withLastName('User')
  .withAge(25)
  .withRole('user')
  .withIsActive(true)
  .build();

E-commerce Product Example

Input Types:

typescript
// types/product.ts
export interface Category {
  id: string;
  name: string;
  description?: string;
}

export interface Product {
  id: string;
  name: string;
  description: string;
  price: number;
  currency: string;
  category: Category;
  tags: string[];
  inStock: boolean;
  inventory: {
    quantity: number;
    reserved: number;
    available: number;
  };
  dimensions?: {
    length: number;
    width: number;
    height: number;
    weight: number;
  };
  createdAt: Date;
  updatedAt: Date;
}

Builder Usage:

typescript
import { product } from './builders/product.builder.js';
import { category } from './builders/category.builder.js';

// Create a complete product with nested category
const laptop = product()
  .withId('prod-001')
  .withName('MacBook Pro 16"')
  .withDescription('High-performance laptop for professionals')
  .withPrice(2499.99)
  .withCurrency('USD')
  .withCategory(
    category()
      .withId('cat-electronics')
      .withName('Electronics')
      .withDescription('Electronic devices and gadgets'),
  )
  .withTags(['laptop', 'apple', 'professional', 'high-performance'])
  .withInStock(true)
  .withInventory({
    quantity: 50,
    reserved: 5,
    available: 45,
  })
  .withDimensions({
    length: 35.79,
    width: 24.59,
    height: 1.68,
    weight: 2.15,
  })
  .withCreatedAt(new Date())
  .withUpdatedAt(new Date())
  .build();

// Create a simple product without optional fields
const simpleProduct = product()
  .withId('prod-002')
  .withName('USB Cable')
  .withDescription('Standard USB-C cable')
  .withPrice(19.99)
  .withCurrency('USD')
  .withCategory(category().withId('cat-accessories').withName('Accessories'))
  .withTags(['cable', 'usb', 'accessory'])
  .withInStock(true)
  .withInventory({
    quantity: 100,
    reserved: 0,
    available: 100,
  })
  .withCreatedAt(new Date())
  .withUpdatedAt(new Date())
  .build();

Advanced Examples

Nested Data Structures

Input Types:

typescript
// types/blog.ts
export interface Author {
  id: string;
  name: string;
  email: string;
  bio?: string;
  avatar?: string;
}

export interface Comment {
  id: string;
  content: string;
  author: Author;
  createdAt: Date;
  updatedAt?: Date;
  likes: number;
  replies: Comment[];
}

export interface BlogPost {
  id: string;
  title: string;
  slug: string;
  content: string;
  excerpt: string;
  author: Author;
  tags: string[];
  categories: string[];
  comments: Comment[];
  publishedAt?: Date;
  updatedAt: Date;
  meta: {
    views: number;
    likes: number;
    shares: number;
  };
}

Builder Usage with Deep Nesting:

typescript
import { blogPost } from './builders/blog-post.builder.js';
import { author } from './builders/author.builder.js';
import { comment } from './builders/comment.builder.js';

// Create a complete blog post with nested comments
const post = blogPost()
  .withId('post-001')
  .withTitle('Advanced TypeScript Patterns')
  .withSlug('advanced-typescript-patterns')
  .withContent('Full article content here...')
  .withExcerpt('Learn advanced TypeScript patterns...')
  .withAuthor(
    author()
      .withId('author-001')
      .withName('Jane Developer')
      .withEmail('jane@example.com')
      .withBio('Senior TypeScript developer')
      .withAvatar('https://example.com/avatar.jpg'),
  )
  .withTags(['typescript', 'patterns', 'advanced'])
  .withCategories(['Programming', 'TypeScript'])
  .withComments([
    comment()
      .withId('comment-001')
      .withContent('Great article! Very helpful.')
      .withAuthor(
        author()
          .withId('commenter-001')
          .withName('Code Reader')
          .withEmail('reader@example.com'),
      )
      .withCreatedAt(new Date())
      .withLikes(5)
      .withReplies([
        comment()
          .withId('reply-001')
          .withContent('I agree, excellent examples!')
          .withAuthor(
            author()
              .withId('commenter-002')
              .withName('Another Reader')
              .withEmail('another@example.com'),
          )
          .withCreatedAt(new Date())
          .withLikes(2)
          .withReplies([]),
      ]),
    comment()
      .withId('comment-002')
      .withContent('Could you elaborate on the factory pattern?')
      .withAuthor(
        author()
          .withId('commenter-003')
          .withName('Curious Developer')
          .withEmail('curious@example.com'),
      )
      .withCreatedAt(new Date())
      .withLikes(3)
      .withReplies([]),
  ])
  .withUpdatedAt(new Date())
  .withMeta({
    views: 1250,
    likes: 89,
    shares: 23,
  })
  .build();

API Response Structures

Input Types:

typescript
// types/api.ts
export interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
  timestamp: Date;
  requestId: string;
  metadata?: {
    version: string;
    processingTime: number;
    cached: boolean;
  };
}

export interface PaginatedResponse<T> {
  items: T[];
  pagination: {
    page: number;
    pageSize: number;
    total: number;
    totalPages: number;
    hasNext: boolean;
    hasPrevious: boolean;
  };
}

export interface ErrorResponse {
  code: string;
  message: string;
  details?: Record<string, unknown>;
  timestamp: Date;
}

Builder Usage for API Mocking:

typescript
import { apiResponse } from './builders/api-response.builder.js';
import { paginatedResponse } from './builders/paginated-response.builder.js';
import { errorResponse } from './builders/error-response.builder.js';

// Success response with data
const userListResponse = apiResponse<PaginatedResponse<User>>()
  .withData(
    paginatedResponse<User>()
      .withItems([
        user().withId('1').withName('Alice').build(),
        user().withId('2').withName('Bob').build(),
        user().withId('3').withName('Charlie').build(),
      ])
      .withPagination({
        page: 1,
        pageSize: 10,
        total: 45,
        totalPages: 5,
        hasNext: true,
        hasPrevious: false,
      }),
  )
  .withStatus(200)
  .withMessage('Users retrieved successfully')
  .withTimestamp(new Date())
  .withRequestId('req-12345')
  .withMetadata({
    version: '1.0.0',
    processingTime: 125,
    cached: false,
  })
  .build();

// Error response
const notFoundResponse = apiResponse<null>()
  .withData(null)
  .withStatus(404)
  .withMessage('User not found')
  .withTimestamp(new Date())
  .withRequestId('req-67890')
  .build();

// Complex error with details
const validationErrorResponse = apiResponse<ErrorResponse>()
  .withData(
    errorResponse()
      .withCode('VALIDATION_ERROR')
      .withMessage('Invalid input data')
      .withDetails({
        field: 'email',
        error: 'Invalid email format',
        value: 'invalid-email',
      })
      .withTimestamp(new Date()),
  )
  .withStatus(400)
  .withMessage('Validation failed')
  .withTimestamp(new Date())
  .withRequestId('req-11111')
  .build();

Testing Examples

Unit Test Data Creation

typescript
// tests/user.test.ts
import { describe, it, expect } from 'vitest';
import { user } from '../builders/user.builder.js';
import { UserService } from '../services/user.service.js';

describe('UserService', () => {
  it('should create a new user', async () => {
    // Arrange
    const userData = user()
      .withUsername('testuser')
      .withEmail('test@example.com')
      .withFirstName('Test')
      .withLastName('User')
      .withAge(25)
      .withRole('user')
      .withIsActive(true)
      .withCreatedAt(new Date())
      .build();

    const userService = new UserService();

    // Act
    const result = await userService.createUser(userData);

    // Assert
    expect(result.username).toBe('testuser');
    expect(result.email).toBe('test@example.com');
    expect(result.isActive).toBe(true);
  });

  it('should handle admin user creation', async () => {
    const adminData = user()
      .withUsername('admin')
      .withEmail('admin@company.com')
      .withRole('admin')
      .withIsActive(true)
      // Use conditional logic for admin-specific setup
      .if(u => u.peek('role') === 'admin', 'lastLoginAt', new Date())
      .build();

    const userService = new UserService();
    const result = await userService.createUser(adminData);

    expect(result.role).toBe('admin');
    expect(result.lastLoginAt).toBeDefined();
  });
});

Integration Test Data

typescript
// tests/integration/order.integration.test.ts
import { order } from '../builders/order.builder.js';
import { orderItem } from '../builders/order-item.builder.js';
import { customer } from '../builders/customer.builder.js';
import { product } from '../builders/product.builder.js';

describe('Order Integration Tests', () => {
  it('should process a complete order', async () => {
    // Create test customer
    const testCustomer = customer()
      .withId('customer-test')
      .withName('Test Customer')
      .withEmail('customer@test.com')
      .withAddress({
        street: '123 Test St',
        city: 'Test City',
        postalCode: '12345',
        country: 'Test Country',
      })
      .build();

    // Create test products
    const laptop = product()
      .withId('prod-laptop')
      .withName('Test Laptop')
      .withPrice(999.99)
      .build();

    const mouse = product()
      .withId('prod-mouse')
      .withName('Test Mouse')
      .withPrice(29.99)
      .build();

    // Create order with items
    const testOrder = order()
      .withId('order-test')
      .withCustomer(testCustomer)
      .withItems([
        orderItem().withProduct(laptop).withQuantity(1).withPrice(laptop.price),
        orderItem().withProduct(mouse).withQuantity(2).withPrice(mouse.price),
      ])
      .withStatus('pending')
      .withCreatedAt(new Date())
      .build();

    // Process the order
    const orderService = new OrderService();
    const result = await orderService.processOrder(testOrder);

    expect(result.status).toBe('processed');
    expect(result.items).toHaveLength(2);
    expect(result.total).toBe(1059.97); // 999.99 + (29.99 * 2)
  });
});

Real-World Scenarios

Configuration Objects

Input Types:

typescript
// types/config.ts
export interface DatabaseConfig {
  host: string;
  port: number;
  database: string;
  username: string;
  password: string;
  ssl: boolean;
  pool: {
    min: number;
    max: number;
    idle: number;
  };
}

export interface CacheConfig {
  type: 'redis' | 'memory' | 'memcached';
  host?: string;
  port?: number;
  ttl: number;
  maxSize?: number;
}

export interface AppConfig {
  env: 'development' | 'staging' | 'production';
  port: number;
  host: string;
  database: DatabaseConfig;
  cache: CacheConfig;
  logging: {
    level: 'debug' | 'info' | 'warn' | 'error';
    format: 'json' | 'text';
    outputs: ('console' | 'file' | 'syslog')[];
  };
  features: {
    enableAuth: boolean;
    enableCors: boolean;
    enableMetrics: boolean;
    enableSwagger: boolean;
  };
}

Configuration Builder Usage:

typescript
import { appConfig } from './builders/app-config.builder.js';
import { databaseConfig } from './builders/database-config.builder.js';
import { cacheConfig } from './builders/cache-config.builder.js';

// Development configuration
const devConfig = appConfig()
  .withEnv('development')
  .withPort(3000)
  .withHost('localhost')
  .withDatabase(
    databaseConfig()
      .withHost('localhost')
      .withPort(5432)
      .withDatabase('app_dev')
      .withUsername('dev_user')
      .withPassword('dev_password')
      .withSsl(false)
      .withPool({
        min: 2,
        max: 10,
        idle: 30000,
      }),
  )
  .withCache(cacheConfig().withType('memory').withTtl(300).withMaxSize(1000))
  .withLogging({
    level: 'debug',
    format: 'text',
    outputs: ['console'],
  })
  .withFeatures({
    enableAuth: true,
    enableCors: true,
    enableMetrics: false,
    enableSwagger: true,
  })
  .build();

// Production configuration
const prodConfig = appConfig()
  .withEnv('production')
  .withPort(8080)
  .withHost('0.0.0.0')
  .withDatabase(
    databaseConfig()
      .withHost(process.env.DB_HOST!)
      .withPort(parseInt(process.env.DB_PORT!))
      .withDatabase(process.env.DB_NAME!)
      .withUsername(process.env.DB_USER!)
      .withPassword(process.env.DB_PASSWORD!)
      .withSsl(true)
      .withPool({
        min: 5,
        max: 50,
        idle: 60000,
      }),
  )
  .withCache(
    cacheConfig()
      .withType('redis')
      .withHost(process.env.REDIS_HOST!)
      .withPort(parseInt(process.env.REDIS_PORT!))
      .withTtl(3600),
  )
  .withLogging({
    level: 'info',
    format: 'json',
    outputs: ['console', 'file'],
  })
  .withFeatures({
    enableAuth: true,
    enableCors: false,
    enableMetrics: true,
    enableSwagger: false,
  })
  .build();

State Management

Input Types:

typescript
// types/state.ts
export interface LoadingState {
  isLoading: boolean;
  operation?: string;
  progress?: number;
}

export interface ErrorState {
  hasError: boolean;
  message?: string;
  code?: string;
  details?: Record<string, unknown>;
}

export interface UserState {
  currentUser?: User;
  isAuthenticated: boolean;
  permissions: string[];
  preferences: UserPreferences;
}

export interface AppState {
  loading: LoadingState;
  error: ErrorState;
  user: UserState;
  router: {
    currentRoute: string;
    previousRoute?: string;
    params: Record<string, string>;
  };
  ui: {
    theme: 'light' | 'dark';
    sidebar: {
      isOpen: boolean;
      width: number;
    };
    notifications: Notification[];
  };
}

State Builder Usage:

typescript
import { appState } from './builders/app-state.builder.js';
import { userState } from './builders/user-state.builder.js';
import { loadingState } from './builders/loading-state.builder.js';

// Initial application state
const initialState = appState()
  .withLoading(loadingState().withIsLoading(false))
  .withError({
    hasError: false,
  })
  .withUser(
    userState().withIsAuthenticated(false).withPermissions([]).withPreferences({
      theme: 'light',
      language: 'en',
      notifications: true,
    }),
  )
  .withRouter({
    currentRoute: '/',
    params: {},
  })
  .withUi({
    theme: 'light',
    sidebar: {
      isOpen: false,
      width: 250,
    },
    notifications: [],
  })
  .build();

// Loading state
const loadingAppState = appState(initialState)
  .withLoading(
    loadingState()
      .withIsLoading(true)
      .withOperation('Fetching user data')
      .withProgress(45),
  )
  .build();

// Authenticated state
const authenticatedState = appState(initialState)
  .withUser(
    userState()
      .withCurrentUser(
        user()
          .withId('user-123')
          .withName('John Doe')
          .withEmail('john@example.com'),
      )
      .withIsAuthenticated(true)
      .withPermissions(['read', 'write'])
      .withPreferences({
        theme: 'dark',
        language: 'en',
        notifications: true,
      }),
  )
  .withUi({
    theme: 'dark',
    sidebar: {
      isOpen: true,
      width: 300,
    },
    notifications: [],
  })
  .build();

Tips and Best Practices

1. Use Factories for Common Patterns

typescript
// factories/user-factory.ts
export class UserFactory {
  static admin(overrides?: Partial<User>): User {
    return user()
      .withRole('admin')
      .withIsActive(true)
      .withPermissions(['read', 'write', 'admin'])
      .withCreatedAt(new Date())
      ...Object.entries(overrides || {}).reduce(
        (builder, [key, value]) => builder.set(key as keyof User, value),
        user()
      )
      .build();
  }

  static guest(): User {
    return user()
      .withRole('guest')
      .withIsActive(false)
      .withPermissions(['read'])
      .withCreatedAt(new Date())
      .build();
  }
}

2. Leverage Conditional Logic

typescript
const user = user()
  .withUsername('testuser')
  .withEmail('test@example.com')
  // Set admin privileges conditionally
  .if(u => process.env.NODE_ENV === 'test', 'role', 'admin')
  .ifElse(
    u => u.peek('role') === 'admin',
    'permissions',
    ['read', 'write', 'admin'],
    ['read'],
  )
  .build();

3. Use Partial Initial Data

typescript
// Start with common base data
const baseUser = {
  createdAt: new Date(),
  isActive: true,
  role: 'user' as const,
};

const specificUser = user(baseUser)
  .withId('specific-123')
  .withUsername('specific')
  .withEmail('specific@example.com')
  .build();

4. Builder Composition Patterns

typescript
// Compose complex objects step by step
const order = order()
  .withCustomer(createTestCustomer())
  .withItems(createTestItems())
  .withShipping(createShippingInfo())
  .withPayment(createPaymentInfo())
  .build();

function createTestCustomer() {
  return customer().withName('Test Customer').withEmail('test@example.com');
}

function createTestItems() {
  return [
    orderItem().withProduct(createLaptop()).withQuantity(1),
    orderItem().withProduct(createMouse()).withQuantity(2),
  ];
}

These examples demonstrate the flexibility and power of fluent-gen-ts for creating type-safe, maintainable object builders in real-world scenarios.

Released under the MIT License.