Last active
February 2, 2020 09:40
-
-
Save danieldietrich/dd352b89b00f4a8e77be01ab1ae22385 to your computer and use it in GitHub Desktop.
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 {}.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}) | |
}; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
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