Created
June 10, 2022 19:08
-
-
Save bolencki13/95fc574742a29ff4d8f14b7a7c959c66 to your computer and use it in GitHub Desktop.
Expose promise methods on a class that resolve type T
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
/** | |
* Exposes internal promise methods on the class that resolves a result of type T | |
*/ | |
abstract class PromiseBuilder<T> implements Promise<T> { | |
/** | |
* Result to be returned when builder is resolved | |
*/ | |
protected abstract _fetchResult(): Promise<T> | |
/** | |
* Exposes traditional promise methods to the class | |
*/ | |
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2> { | |
const result = this._fetchResult() | |
return result.then.apply(result, [onfulfilled, onrejected]) as any | |
} | |
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult> { | |
return this.then().catch(onrejected) | |
} | |
finally(onfinally?: (() => void) | undefined | null): Promise<T> { | |
return this.then().finally(onfinally) | |
} | |
get [Symbol.toStringTag]() { | |
return this.constructor.name; | |
} | |
} | |
/** | |
* Example: | |
*/ | |
type Pizza = { | |
crust: 'thin' | 'regular'; | |
cheese: boolean; | |
sauce: 'none' | 'white' | 'red'; | |
toppings: string[]; | |
} | |
class PizzaBuilder extends PromiseBuilder<Pizza> { | |
protected _pizza: Pizza = { | |
crust: 'regular', | |
cheese: true, | |
sauce: 'red', | |
toppings: [] | |
} | |
protected _fetchResult(): Promise<Pizza> { | |
return Promise.resolve(this._pizza) | |
} | |
redSauce() { | |
this._pizza.sauce = 'red' | |
return this | |
} | |
whiteSauce() { | |
this._pizza.sauce = 'white' | |
return this | |
} | |
noSauce() { | |
this._pizza.sauce = 'none' | |
return this | |
} | |
cheese(shouldHaveCheese: boolean) { | |
this._pizza.cheese = shouldHaveCheese | |
return this | |
} | |
thinCrust() { | |
this._pizza.crust = 'thin' | |
return this; | |
} | |
regularCrust() { | |
this._pizza.crust = 'regular' | |
return this; | |
} | |
addTopping(topping: string) { | |
this._pizza.toppings.push(topping); | |
return this | |
} | |
removeTopping(topping: string) { | |
this._pizza.toppings = this._pizza.toppings.filter((t) => t !== topping); | |
return this | |
} | |
} | |
async function main() { | |
let builder = new PizzaBuilder() | |
builder = builder | |
.addTopping('pepperoni') | |
const pizza1 = await builder | |
console.log(pizza1) // {"crust":"regular","cheese":true,"sauce":"red","toppings":["pepperoni"]} | |
const pizza2 = await builder | |
.removeTopping('pepperoni') | |
.whiteSauce() | |
.thinCrust() | |
.addTopping('chicken') | |
.addTopping('broccoli') | |
console.log(pizza2) // {"crust":"thin","cheese":true,"sauce":"white","toppings":["chicken","broccoli"]} | |
} | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment