使用TypeScript接口的构建器模式

时间:2017-07-24 23:34:09

标签: typescript

我想做这样的事情:

interface IPoint {
    x : number;
    y : number;
    z? : number;
}
const diag : IPoint = IPoint.x(1)
                            .y(2)
                            .build();

我意识到我可以自己实现这个,但是想知道是否有自动方法来做到这一点?给定TypeScript已经知道类型信息。

编辑:我正在请求这种语法,因为我目前可以这样做。

const diag : IPoint = {x: 1, y: 1};

3 个答案:

答案 0 :(得分:8)

这处理类型:

interface IPoint {
    x: number;
    y: number;
    z?: number;
}

type IBuilder<T> = {
    [k in keyof T]: (arg: T[k]) => IBuilder<T>
} & { build(): T }


let builder = {} as IBuilder<IPoint>

const diag = builder.x(1).y(2).z(undefined).build()

但我不知道你将如何创造实际Builder你。 :)

您可以在playground

进行游戏 编辑:Vincent Peng创建了一个builder-pattern npm包(如评论中所述)。去吧,给它一些爱!

答案 1 :(得分:5)

以下设计通过完成三件事来增加类型安全性:

  1. 它知道已经提供了哪些必需的属性。
  2. 知道已经提供了哪些可选属性。
  3. 仅在提供所有必需的属性后,您才能build

Point本身:

interface Point {
  x: number;
  y: number;
  z?: number;
}

class Point implements Point {
  constructor(point: Point) {
    Object.assign(this, point);
  }
}

Point构建器:

class PointBuilder implements Partial<Point> {
  x?: number;
  y?: number;
  z?: number;

  withX(value: number): this & Pick<Point, 'x'> {
    return Object.assign(this, { x: value });
  }

  withY(value: number): this & Pick<Point, 'y'> {
    return Object.assign(this, { y: value });
  }

  withZ(value: number): this & Required<Pick<Point, 'z'>> {
    return Object.assign(this, { z: value });
  }

  build(this: Point) {
    return new Point(this);
  }
}

用法:

/**
 * The `z` property is optional.
 */
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

答案 2 :(得分:1)

根据先前的答案,我编写了一个通用的Typescript构建器,该构建器提供:

  • 类型安全
  • 可选必需属性的区别
  • 用于添加对象部分的通用方法( with
  • 验证对象之前创建
  • 域驱动设计一致性(使用Builder时无需指定方法)

如果您有兴趣,可以在这里找到更多信息和示例: https://github.com/hanterlantant/ts-generic-builder 和npm包在这里: https://www.npmjs.com/package/ts-generic-builder