繁体   English   中英

我应该如何 go 关于 TypeScript 中的方法链接(就像 Tiptap 的做法一样)

[英]How should I go about method chaining in TypeScript (like how Tiptap does it)

Tiptap (和许多其他基于ProseMirror的文本编辑器)有这个惊人的 API,我们可以在其中链接命令。

例如

editor.chain().focus().toggleItalic().run()

在这里,调用chain()返回所有可链接的命令,这些命令本身返回可链接的命令,这就是链如何继续,直到你调用run()

调用run()后, chain()run()之间的命令会同步执行。

有趣的是(据我所知)这不是 class。 所有这些也可以通过为 Tiptap 创建自定义扩展来扩展(包括打字)。 请参阅此粗体扩展及其类型

我通过那里的来源做了 go 但无法理解太多。

我真的很喜欢这种设计模式,并且想知道我应该如何 go 来实现这个一般...

说,我想在这个模式上实现一个计算器。 我怎样才能使这条线工作?

calculator.chain().setValue(10).add(3).sub(12).run() // 1

谢谢!

有很多方法可以实现这一点,这里只是一个简单的 object。 class 封装可能是个好主意。 只要您将方法包含在单个 object 中,您就可以继续返回它并添加到回调队列中,最终将在.run()上执行并打破循环。

const calculator = {
  state: { value: 0 },
  callbacks: [] as ((...args: any[]) => any)[],
  _exec: {
    setValue: (val: number) => (calculator.state.value = val),
    add: (val: number) => (calculator.state.value += val),
    sub: (val: number) => (calculator.state.value -= val),
  },
  _queue: {
    setValue: (val: number) => {
      calculator.callbacks.push(() => calculator._exec.setValue(val));
      return calculator._queue;
    },
    add: (val: number) => {
      calculator.callbacks.push(() => calculator._exec.add(val));
      return calculator._queue;
    },
    sub: (val: number) => {
      calculator.callbacks.push(() => calculator._exec.sub(val));
      return calculator._queue;
    },
    run: () => {
      calculator.callbacks.forEach((cb) => cb());
      calculator.callbacks = [];
    },
  },
  chain: () => calculator._queue,
};

calculator.chain().setValue(10).add(3).sub(12).run();
console.log(calculator.state.value); // logs 1

只需使用class

 class Calculator { constructor(value) { this.value = value; } run() { return this.value; } add(x) { return new Calculator(this.value + x); } sub(x) { return new Calculator(this.value - x); } log() { console.log(this.value); return this; } static withValue(v) { return new this(v); } } const calc = Calculator.withValue(10).add(3).log(); console.log(calc.sub(12).run()); console.log(calc.add(29).run());

对于方法链接来说,唯一重要的是返回一个 object,其中包含来自每个可链接方法的所有方法(此处为Calculator实例)。 您也可以在没有class语法的情况下实现相同的目的:

 function calculatorWithValue(v) { return { run() { return v; }, add(x) { return calculatorWithValue(v + x); }, sub(x) { return calculatorWithValue(v - x); }, log() { console.log(v); return this; }, }; } const calc = calculatorWithValue(10).add(3).log(); console.log(calc.sub(12).run()); console.log(calc.add(29).run());

我建议保持对象不可变,以允许创建多个独立链或分叉现有链 - 请参阅上面的示例,其中第二个结果是10 + 3 + 29 ,而不是10 + 3 - 12 + 29

如果你想让执行变得懒惰,那也很容易:

 class Calculator { constructor(run) { this.run = run; } static withValue(v) { return new this(() => v); } add(x) { return new Calculator(() => this.run() + x); } sub(x) { return new Calculator(() => this.run() - x); } log() { return new Calculator(() => { const v = this.run(); console.log(v); return v; }); } } const calc = Calculator.withValue(10).add(3).log(); console.log(calc.sub(12).run()); console.log(calc.add(29).run());

如果您想通过某种插件架构使其可扩展,只需在原型上添加更多方法,或者动态构建 object。 对于 TypeScript,您可以使用声明合并来使用插件提供的签名来修改Calculator接口。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM