Skip to content

Instantly share code, notes, and snippets.

@foxel
Created September 29, 2017 08:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save foxel/7217e1b38ad5c3803c6aa286638d22ea to your computer and use it in GitHub Desktop.
Save foxel/7217e1b38ad5c3803c6aa286638d22ea to your computer and use it in GitHub Desktop.
Phantom Builder in TS
// Inspired by https://medium.com/@maximilianofelice/builder-pattern-in-scala-with-phantom-types-3e29a167e863
export type Pizza = {};
namespace Pizza {
export type WithCheese = {
readonly cheese: string;
};
export type WithTopping = {
readonly topping: string;
};
export type WithDough = {
readonly dough: 'white' | 'black';
};
export type Full = WithCheese & WithTopping & WithDough;
}
class Chief<T extends Pizza> {
constructor(
readonly pizza: T,
) {}
addCheese(cheeseType: string): Chief<T & Pizza.WithCheese> {
return new Chief(Object.assign({}, this.pizza, {
cheese: cheeseType,
}));
}
addTopping(toppingType: string): Chief<T & Pizza.WithTopping> {
return new Chief(Object.assign({}, this.pizza, {
topping: toppingType,
}));
}
addDough(doughType: 'white' | 'black'): Chief<T & Pizza.WithDough> {
return new Chief(Object.assign({}, this.pizza, {
dough: doughType,
}));
}
static startPizza(): Chief<Pizza> {
return new Chief({});
}
}
class Oven {
cookPizza(pizza: Pizza.Full): void {
}
}
const pizzaToCook = Chief.startPizza() // note that if one of these steps is missing, oven will not cook a pizza
.addCheese('Cheddar')
.addDough('white')
.addTopping('Pickle')
.pizza;
new Oven().cookPizza(pizzaToCook);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment