Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// 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));
@startswithaj

This comment has been minimized.

Copy link

@startswithaj startswithaj commented Nov 23, 2018

Hey Jaime, I was at the angular meet up the other night and saw you talk on these builders. Do you have any real world usage examples?

What would be the advantage of using these instead of conventionally creating a typed object?

const x: RequestSettings = {
  protocol: 'http',
  host: 'test.com',
  path: '/foo/bar',
  headers: []
}

Also in your example on the night one of your builders had an extend method that allowed you to pass an object of {k:v}. Do you have that code handy?

@MAXruppert

This comment has been minimized.

Copy link

@MAXruppert MAXruppert commented May 30, 2020

Really enjoyed this utility of typescript generics. Thanks!

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.