如何重用链式函数 Javascript + Typescript

How to reuse chained functions Javascript + Typescript

我正在使用 Typescript 并使用链式方法创建表单验证库,但由于 this return,我一直在尝试重用函数,我将以更简单的方式举例说明:

const schema = {
  computer() {
    return {
      turnOn() {
        console.log('turn on')
        return this
      },
      openVscode() {
        console.log('open vscode')

        return this
      },
      work() {
        console.log('work')
        return this
      },
      turnOff() {
        console.log('turn off')
        return this
      }
    }
  },
  phone() {
    return {
      turnOn() {
        console.log('turn on')
        return this
      },
      takeSelfies() {
        console.log('take selfies')

        return this
      },
      callToMom() {
        console.log('call to mom')
        return this
      },
      turnOff() {
        console.log('turn off')
        return this
      }
    }
  }
}

一切正常。

const devices = {
  iMac: schema.computer().turnOn().openVscode().work().turnOff(),
  iPhone: schema.phone().turnOn().takeSelfies().callToMom().turnOff()
}

但是当我尝试在另一个文件中分隔重复的函数时,例如

const mixed = {
  turnOn() {
    console.log('turn on')
    return this
  },
  turnOff() {
    console.log('turn off')
    return this
  }
}

重用

const newSchema = {
  computer() {
    return {
      ...mixed,
      openVscode() {
        console.log('open vscode')

        return this
      },
      work() {
        console.log('work')
        return this
      }
    }
  },
  phone() {
    return {
      ...mixed,
      takeSelfies() {
        console.log('take selfies')

        return this
      },
      callToMom() {
        console.log('call to mom')
        return this
      }
    }
  }
}

我卡住了

我知道这是因为 mixed 对象的 this return 只有内容本身,但我不知道如何解决这个问题。

谢谢大家!

这是称为 Mixins and is developed in typescript as Decorators

的模式示例

基本思想是将两个 类 连接在一起以提供类似于经典继承的功能。它从对象属性的简单复制开始——但可以发展成使用闭包在不同级别提供混合的函数。

这是一个概念证明:

utility = {foo: function() {return this}}
main = {bar: function() {return this}}

main = Object.assign(main, utility);

console.log(main.foo());

captain-yossarian 和 Charlie 关于 mixins 的观点很好,如果你想使用它们,值得研究。但是,这里有一个不需要对原始代码进行太多重构的解决方案:

const mixed = { /* same as before */ }

type AnyFn = (...args: never[]) => unknown

type SetReturnTypes<T extends Record<string, AnyFn>> = {
  [K in keyof T]: (...args: Parameters<T[K]>) => SetReturnTypes<T>
}

const makeMixed = <T>(obj: T & ThisType<T & typeof mixed>): SetReturnTypes<T & typeof mixed> => ({
  ...mixed,
  ...obj
}) as unknown as SetReturnTypes<T & typeof mixed>

const newSchema = {
  computer() {
    return makeMixed({
      openVscode() {
        console.log('open vscode')
        return this
      },
      work() {
        console.log('work')
        return this
      }
    })
  },
  phone() {
    return makeMixed({
      takeSelfies() {
        console.log('take selfies')
        return this
      },
      callToMom() {
        console.log('call to mom')
        return this
      }
    })
  }
}

newSchema.computer().turnOn().openVscode()
  • SetReturnTypes 使 T return 的所有方法成为正确的 this 类型,假设所有这些方法 return this.
  • makeMixed 是一个帮助程序,用于创建具有正确类型的 mixed 对象。它使用 ThisType 以便 obj 中的方法具有正确的 this 类型:
makeMixed({
  doSomething() {
    this.turnOn() // would be a compile error without the ThisType
    return this
  }
})

一个问题是未 returning this 的方法类型不正确。如果你想确保所有的方法 return this,请告诉我,我可能会想出一个解决方案。

Playground link