สร้าง Builder Pattern แบบ Type-Safe
Basic
class Inventory<Items extends Record<string, unknown> = {}> {
items: Items = {} as Items;
add<NewItem extends Record<string, unknown>>(value: NewItem) {
this.items = {
...value as unknown as Items
}
return this as Inventory<Items & NewItem>;
}
}
const inventory = new Inventory()
.add({
hello: 'world',
}).add({
typescript: 5.1,
numbers: [23, '123']
});
console.log(inventory.items.typescript)
type A = typeof inventory.items;
// type A = {
// hello: string;
// } & {
// typescript: number;
// numbers: (string | number)[];
// }
Ref: TypeScript Meetup Thailand July 2023 https://www.facebook.com/phantipk/videos/289991566938840?idorvanity=1377224595918442
More advanced
class ObjectBuilder<Items extends Record<string, unknown> = {}> {
constructor(private readonly jsonObject: Items) { }
add<K extends string, V>(key: K, value: V) {
const nextPart = { [key]: value } as Record<K, V>;
return new ObjectBuilder({ ...this.jsonObject, ...nextPart }) as
ObjectBuilder<{ [Key in keyof (Items & Record<K, V>)]: (Items & Record<K, V>)[Key] }>;
}
build(): Items {
return this.jsonObject;
}
static create(){
return new ObjectBuilder({});
}
}
const json = ObjectBuilder.create()
.add('aString', 'some text')
.add('aNumber', 2)
.add('anArray', [1, 2, 3])
.build();
type B = typeof json;
// type B = {
// aString: string;
// aNumber: number;
// anArray: number[];
// }
Ref: https://medium.hexlabs.io/the-builder-pattern-with-typescript-using-advanced-types-e05a03ffc36e