Skip to content
Please note that GitHub no longer supports Internet Explorer.

We recommend upgrading to the latest Microsoft Edge, Google Chrome, or Firefox.

Learn more

Instantly share code, notes, and snippets.

@danieldietrich danieldietrich/builder.ts
Last active Feb 2, 2020

Embed
What would you like to do?
A generic functional object builder. Builders are used in the presence of default values or if objects are created in multiple steps. Otherwise you would create them directly using the object literal {}.
type Builder<T> = {
with: (t: Partial<T>) => Builder<T>,
build: () => T
}
// A generic builder that works for *ALL* object types
function builder<T>(options: { defaultValues: T }): Builder<T> {
return {
with: _with,
build: () => ({...options.defaultValues})
};
function _with(t1: Partial<T>): Builder<T> {
return {
with: t2 => _with({...t1, ...t2}),
build: () => ({...options.defaultValues, ...t1})
};
}
}
// Example application
type Person = {
forename: string
surname: string
phone?: number
address?: Address[]
}
type Address = {
street?: string
zip?: number
city?: string
country?: 'foo' | 'bar' | 'baz'
}
const personBuilder = builder<Person>({ defaultValues: { forename: "(unknown)", surname: "(unknown)" }});
const addressBuilder = builder<Address>({ defaultValues: {}});
// inferred type: Person
const daniel = personBuilder
.with({ forename: 'Daniel', surname: 'Dietrich' }) // setting multiple attributes at once
.with({ phone: 123 })
.with({ address: [
addressBuilder.with({ street: 'Milkyway', country: 'foo' }).build(), // setting only some optional attributes
addressBuilder.with({ street: 'Elmstreet', country: 'bar' }).build()
]})
.build();
{
forename: 'Daniel',
surname: 'Dietrich',
phone: 123,
address: [
{ street: 'Milkyway', country: 'foo' },
{ street: 'Elmstreet', country: 'bar' }
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.