Skip to content

Instantly share code, notes, and snippets.

@karol-majewski
Last active September 18, 2022 14:31
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save karol-majewski/1d2aee6b25892c7285555fda31327ba8 to your computer and use it in GitHub Desktop.
Save karol-majewski/1d2aee6b25892c7285555fda31327ba8 to your computer and use it in GitHub Desktop.
Builder pattern in TypeScript (https://stackoverflow.com/a/53982272/10325032)
/**
* The shape we are building.
*/
interface IPoint {
x: number;
y: number;
z?: number;
}
class Point implements IPoint {
x: number;
y: number;
z?: number;
constructor(point: IPoint) {
this.x = point.x;
this.y = point.y;
this.y = point.y;
}
}
/**
* Accumulates data, and only lets you `build()` when all requirements are met.
*/
class PointBuilder implements Partial<IPoint> {
x?: number;
y?: number;
z?: number;
withX(value: number): this & Pick<IPoint, 'x'> {
return Object.assign(this, { x: value });
}
withY(value: number): this & Pick<IPoint, 'y'> {
return Object.assign(this, { y: value });
}
withZ(value: number): this & Required<Pick<IPoint, 'z'>> {
return Object.assign(this, { z: value });
}
build(this: IPoint) {
return new Point(this);
}
}
/**
* The `z` property doesn't have to be provided.
*/
new PointBuilder()
.withX(1)
.withY(1)
.build();
/**
* The `.build()` method cannot be called — we are still missing `y`.
*/
new PointBuilder()
.withX(1)
.withZ(1);
/**
* The `z` property is correctly recognized as `number` (as opposed to `number | undefined`)
*/
new PointBuilder()
.withX(1)
.withZ(1)
.z
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment