I have successfully implemented a Builder design pattern in TypeScript for certain entities. One of these implementations is shown below (simplified), and can also be accessed in the playground:
type Shape = any;
type Slide = any;
type Animation = any;
export class SlideBuilder {
private slide: Slide;
public static start() { return new SlideBuilder(); }
public withShape(name: string, shape: Shape): this {
this.slide.addShape(name, shape);
return this;
}
public withAnimation(name: string, animation: Animation): this {
this.slide.addAnimation(name, animation);
return this;
}
public withOrder(shape: string, animations: string[]) {
this.slide.addOrder(shape, animations);
return this;
}
}
SlideBuilder
.start()
.withShape("Hello World", {})
.withAnimation("Animation1", {})
.withAnimation("Animation2", {})
.withOrder("Could be 'Hello World' only", ["Could be 'Animation1' or 'Animation2' only"])
The challenge I am facing now is to enforce type checking to ensure that the withOrder
method is called with correct parameters that were previously passed to withShape
or withAnimation
.
I attempted to introduce generic types to the class like so:
export class SlideBuilder<S, A> {
withShape(name: S, shape: Shape)
withAnimation(name: A, animation: Animation)
withOrder(shape: S, animation: A[])
}
However, I could not figure out how to keep track of each call, such as collecting the types from individual calls into a union type. It seems necessary to somehow specify
withOrder(shape: S1 | S2 | S3 | ... | Sn)
, where Sn
is a type from the withShape
call. If you have any insight on how to effectively implement this, please share your thoughts.