TYPESCRIPT

Builder Pattern with Fluent API

Type-safe builder pattern for complex object creation

TypeScriptDesign PatternsBuilder

Code

// Base Builder interface
type Builder<T> = {
  [K in keyof T]-?: (value: T[K]) => Builder<T>;
} & {
  build(): T;
};

// Generic builder creator
function createBuilder<T>(): Builder<T> {
  const built: Partial<T> = {};
  
  const handler: ProxyHandler<object> = {
    get(target, prop: string) {
      __TOKEN_52__ (prop === 'build') {
        __TOKEN_53__ () => {
          // Validate required fields here if needed
          return built as T;
        };
      }
      
      __TOKEN_55__ (value: any) => {
        built[prop as keyof T] = value;
        return proxy;
      };
    }
  };
  
  const proxy = new Proxy({}, handler);
  return proxy as Builder<T>;
}

// Example: User builder
interface User {
  id: number;
  name: string;
  email: string;
  age?: number;
  roles: string[];
  metadata: Record<string, any>;
}

// Specific builder with validation
class UserBuilder {
  private user: Partial<User> = {
    roles: [],
    metadata: {},
  };
  
  withId(id: number): this {
    this.user.id = id;
    return this;
  }
  
  withName(name: string): this {
    __TOKEN_68__ (name.length < 2) {
      throw new Error('Name must be at least 2 characters');
    }
    this.user.name = name;
    return this;
  }
  
  withEmail(email: string): this {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    __TOKEN_76__ (!emailRegex.test(email)) {
      throw new Error('Invalid email address');
    }
    this.user.email = email;
    return this;
  }
  
  withAge(age: number): this {
    __TOKEN_83__ (age < 0 || age > 150) {
      throw new Error('Age must be between 0 and 150');
    }
    this.user.age = age;
    return this;
  }
  
  addRole(role: string): this {
    this.user.roles!.push(role);
    return this;
  }
  
  withMetadata(key: string, value: any): this {
    this.user.metadata![key] = value;
    return this;
  }
  
  build(): User {
    // Validate required fields
    __TOKEN_97__ (!this.user.id || !this.user.name || !this.user.email) {
      throw new Error('Missing required fields');
    }
    
    return this.user as User;
  }
}

// Advanced: Step builder pattern
interface QueryBuilder {
  select(...columns: string[]): QueryBuilder;
  __TOKEN_106__(table: string): QueryBuilder;
  where(condition: string): QueryBuilder;
  orderBy(column: string, direction?: 'ASC' | 'DESC'): QueryBuilder;
  limit(count: number): QueryBuilder;
  build(): string;
}

class SQLQueryBuilder implements QueryBuilder {
  private query = {
    select: [] as string[],
    from: '',
    where: [] as string[],
    orderBy: [] as string[],
    limit: null as number | null,
  };
  
  select(...columns: string[]): this {
    this.query.select = columns;
    return this;
  }
  
  __TOKEN_115__(table: string): this {
    this.query.from = table;
    return this;
  }
  
  where(condition: string): this {
    this.query.where.push(condition);
    return this;
  }
  
  andWhere(condition: string): this {
    this.query.where.push(`AND ${condition}`);
    return this;
  }
  
  orWhere(condition: string): this {
    this.query.where.push(`OR ${condition}`);
    return this;
  }
  
  orderBy(column: string, direction: 'ASC' | 'DESC' = 'ASC'): this {
    this.query.orderBy.push(`${column} ${direction}`);
    return this;
  }
  
  limit(count: number): this {
    this.query.limit = count;
    return this;
  }
  
  build(): string {
    __TOKEN_141__ (!this.query.select.length || !this.query.from) {
      throw new Error('SELECT and FROM clauses are required');
    }
    
    const parts = [
      `SELECT ${this.query.select.join(', ')}`,
      `FROM ${this.query.from}`,
    ];
    
    __TOKEN_148__ (this.query.where.length) {
      parts.push(`WHERE ${this.query.where.join(' ')}`);
    }
    
    __TOKEN_150__ (this.query.orderBy.length) {
      parts.push(`ORDER BY ${this.query.orderBy.join(', ')}`);
    }
    
    __TOKEN_152__ (this.query.limit !== null) {
      parts.push(`LIMIT ${this.query.limit}`);
    }
    
    return parts.join('\n');
  }
}

// Usage examples
// Generic builder
const user = createBuilder<User>()
  .id(1)
  .name('John Doe')
  .email('[email protected]')
  .age(30)
  .build();

// Specific builder with validation
const user2 = new UserBuilder()
  .withId(1)
  .withName('Jane Smith')
  .withEmail('[email protected]')
  .addRole('admin')
  .addRole('user')
  .withMetadata('createdAt', new Date())
  .build();

// Query builder
const query = new SQLQueryBuilder()
  .select('id', 'name', 'email')
  .__TOKEN_161__('users')
  .where('age > 18')
  .andWhere('status = "active"')
  .orderBy('name', 'ASC')
  .limit(10)
  .build();