-
-
Save michael-wolfenden/729dd91632334039c4a9c0aeaad29cfd to your computer and use it in GitHub Desktop.
This file contains 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
// Builders | |
class SimpleBuilder { | |
constructor(private current = {}) { | |
} | |
prop(key: string, value: any) { | |
return new SimpleBuilder({ ...this.current, ...{ [key]: value } }); | |
} | |
build<R>() { | |
return <R>this.current; | |
} | |
} | |
class TypedBuilder<T> { | |
constructor(private current = {}) { | |
} | |
prop<P extends keyof T, V extends T[P]>(key: P, value: V) { | |
return new TypedBuilder<T>({ ...this.current, ...{ [key]: value } }); | |
} | |
build() { | |
return <T>this.current; | |
} | |
} | |
class AdvanceBuilder<T, R extends {} = {}> { | |
constructor(private current: R = null) { | |
} | |
// P: Only those properties from T that do not exist in R | |
prop<P extends Exclude<keyof T, keyof R>, V extends T[P]>(key: P, value: V) { | |
let extra: Pick<T, P> = { [key]: value }; | |
// `instance` is an intersection between our accumulator type (R) and | |
// the `extra` object created above | |
let instance = { | |
...(this.current as object), | |
...extra | |
} as R & Pick<T, P>; | |
return new AdvanceBuilder<T, R & Pick<T, P>>(instance); | |
} | |
build(): R { | |
return this.current; | |
} | |
} | |
// Domain | |
interface RequestSettings { | |
protocol: 'http' | 'https'; | |
host: string; | |
path: string; | |
query?: string; | |
headers: { key: string, value: string }[] | |
} | |
// Usage | |
const settings1 = new SimpleBuilder() | |
.prop('protocol', 'http') | |
.prop('host', 'test.com') | |
.prop('path', '/foo/bar') | |
.prop('headers', []) | |
.build<RequestSettings>(); | |
const settings2 = new TypedBuilder<RequestSettings>() | |
.prop('protocol', 'http') | |
.prop('host', 'test.com') | |
.prop('path', '/foo/bar') | |
.prop('headers', []) | |
.build(); | |
const settings3: RequestSettings = new AdvanceBuilder<RequestSettings>() | |
.prop('protocol', 'http') | |
.prop('host', 'test.com') | |
.prop('path', '/foo/bar') | |
.prop('headers', []) | |
.build(); | |
// Logging | |
alert(JSON.stringify(settings1)); | |
alert(JSON.stringify(settings2)); | |
alert(JSON.stringify(settings3)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment