3

编辑我正在使用monocle-ts,但是如果使用 monocle-ts 是不可能的(因为作者甚至说它只是 Scala 原始 Monocle 的部分端口)但是如果在另一个光学包中有任何语言的东西,我愿意将这些想法移植到 TypeScript。)

假设我有一个辅助类型Partial<A>,它表示一个记录,该记录具有类型的部分或全部,但没有非成员A。(所以如果A = { foo: number, bar: string }then Partial<A> = { foo?: number, bar?: string })(编辑这是 Typescript 的内置 Partial 实用程序类型。)

我从

interface Parent {
  xs: Child[]
}

interface PartialParent {
  partialxs: Partial<Child>[]
}

declare function fillInTheGaps(x: Partial<Child>):Child

假设我已经组合了一个镜头并遍历组合 ( composedTraversal) 以便它聚焦于 partialxsfromPartialState然后作为一个数组遍历它。这将是一个Traversal<PartialState, Partial<Child>>.

还假设我有一个declare const fn = (x:Partial<Child>):Partial<Child>然后我可以应用于fn所有孩子,composedTraversal.modify(fn)(partialState)这将产生一个新PartialStatefn应用于所有partialxs.

是否有一些概念可以让我“扩大”或“转换”这个遍历到不同的东西,以便我可以组成镜头和遍历并使用fillInTheGaps,这样我就可以传入PartialState并取回 a State

忽略我的语法是 TypeScript,我添加了 monocle-scala 标签,因为如果这个概念存在,我想它在 Monocle 库中,我可以将这些知识翻译到我正在使用的库中。

编辑激发这个问题的问题是我在 Redux 应用程序中有一个表单输入,用户输入数据但大多数不是必需的。INPUT 在编译时是未知的(它们是从 RESTful API 查询中重试的),所以我不能将模型表示为

interface Model {
  foo?: string[]
  bar?: string[]
}

相反,它表示为

interface Model {
  [index:string]: string[]
}

我还可以从 RESTful 服务器获取默认模型。所以我将这些建模为Parent(来自服务器的Partial<Parent>内容)和(代表用户在应用程序中的输入)。

在进行一些计算之前,我需要为缺少的道具折叠默认值。这是我fillInTheGaps上面引用的函数。

希望通过我的代码中的类型来强制执行此操作,并且因为我已经编写了很多光学元件,所以重用其中的一些。实际上,我编写了一个镜头和遍历来对这些数据执行其他操作。myLens.compose(myTraversal).modify(fn)接受 aPartial<State>并返回 aPartial<State>但我希望将这些组合起来最终得到一个接受部分并返回整体的函数。

我显然可以只写const filler: (Partial<State>):State = myLens.compose(myTraversal).modify(fillInTheGaps)然后//@ts-ignore在它上面扔一个并且知道它会起作用,但这似乎,呃,脆弱。

4

1 回答 1

1

我认为,您可能想要的是多态遍历或PTraversal<S, T, A, B>.

ATraversal<S, A>说,“如果我有一个函数A => A,我可以用它modify来获得一个函数S => S,它使用原始函数来修改所有 A出现在S”中的 s。

相比之下,aPTraversal<S, T, A, B>说,“如果我有一个函数A => B,我可以用它modify来获取一个函数S => T”,这会将所有As转换SB,从而产生 a T

助记符的类型参数为PTraversal

  • S的来源PTraversal
  • T的“修改”来源PTraversal
  • A的目标PTraversal
  • B的“修改”目标PTraversal

PTraversals 很有用,因为它们让您可以编写如下内容:

PTraversal<Array<A>, Array<B>, A, B>

Array让您在更改元素类型的同时遍历。


在您的具体情况下,您提到有两个功能:

declare function fillInTheGaps(x: Partial<Child>):Child
declare function fn(x: Partial<Child>):Partial<Child>

这些可以组合在一起以产生单个功能:

function transformAndFill(x: Partial<Child>): Child {
   return fillInTheGaps(fn(x)); 
}

然后,您需要编写一个PTraversal<PartialState, State, Partial<Child>, Child>.

这将支持用 a 作曲,以与所做的大致相同的方式Lens制作一个新的。PTraversalTraversal

应该是可行的,我认为从您的问题来看,如果您可以将 every Partial<Child>in转换PartialState为 aChild您应该能够制作State.


PTraversal存在于 Monocle(Scala 库)中,但不幸的是,它看起来不像是它monocle-ts:所以不幸的是,您必须编写大量的光学库代码才能支持这一点。

于 2020-09-08T23:25:18.490 回答