How do you create a type-safe builder pattern in TypeScript?

Answer

A type-safe builder pattern uses TypeScript's type system to track what properties have been set and enforce that required properties are provided before the object is built. Using phantom types and conditional types: type HasName = { name: true }; type HasAge = { age: true }; class UserBuilder<T = {}> { private data: Partial<User> = {}; setName(name: string): UserBuilder<T & HasName> { this.data.name = name; return this as any; } setAge(age: number): UserBuilder<T & HasAge> { this.data.age = age; return this as any; } build(this: UserBuilder<HasName & HasAge>): User { return this.data as User; } }. With this, calling build() before setName() and setAge() is a compile-time error: new UserBuilder().setName("Alice").build(); — error, missing age. new UserBuilder().setName("Alice").setAge(30).build(); — valid. Each setter returns a more specific type that tracks progress, and build() requires the intersection of all required phantom types.