(Edit I'm using monocle-ts, but if it's not possible with monocle-ts (since the author even says it's just a partial port of the original Monocle for Scala) but if there is something in another optics package for any language, I'm open to porting those ideas to TypeScript.)
Suppose I have a helper type Partial<A> such that it represents a record that has some or all, but no non-members, of type A. (So if A = { foo: number, bar: string } then Partial<A> = { foo?: number, bar?: string }) (Edit This is Typescript's built-in Partial utility type.)
I begin with
interface Parent {
xs: Child[]
}
interface PartialParent {
partialxs: Partial<Child>[]
}
declare function fillInTheGaps(x: Partial<Child>):Child
Suppose I have composed a lens and traversal composed (composedTraversal) so that it focuses on partialxs from PartialState and then traverses over it as an array. This would be a Traversal<PartialState, Partial<Child>>.
Posit also that I have a declare const fn = (x:Partial<Child>):Partial<Child> then I can apply fn to all children with composedTraversal.modify(fn)(partialState) which will yield a new PartialState with fn applied to all of the partialxs.
Is there some concept that lets me "broaden" or "transform" this traversal into something different so that I could compose the lens and traversal and use fillInTheGaps so I can pass in the PartialState and get back a State?
Ignoring that my syntax is TypeScript, I've added the monocle-scala tag because if this concept exists I imagine it's in the Monocle library and I can translate that knowledge to the library I'm using.
Edit The problem motivating this question is I have a form input in a Redux app where a user inputs data but most is not required. The INPUTs are not known at compile-time (they're retried from a RESTful API query) so I cannot represent the model as
interface Model {
foo?: string[]
bar?: string[]
}
Instead, it is represented as
interface Model {
[index:string]: string[]
}
I can also fetch a default model from the RESTful server. So I've modeled these as Parent (what comes from the server) and Partial<Parent> (what represents the user's input in the app).
Before doing some computations, I need to fold in defaults for the missing props. This is my fillInTheGaps function referenced above.
The desire was to enforce what this does via types in my code and, because I have a lot of optics already written, reuse some of that. I actually have a lens and traversal written to perform other operations on this data. myLens.compose(myTraversal).modify(fn) takes a Partial<State> and returns a Partial<State> but I was hoping to compose these to end up with a function that takes the partial and returns the whole.
I could obviously just write const filler: (Partial<State>):State = myLens.compose(myTraversal).modify(fillInTheGaps) and then throw a //@ts-ignore above it and know it would work, but that seems, uh, fragile.
I think, what you might want is a Polymorphic Traversal or
PTraversal<S, T, A, B>.A
Traversal<S, A>says, "If I have a functionA => A, I can usemodifyto obtain a functionS => Sthat uses the original function to modify all of theAs that appear inS".By comparison, a
PTraversal<S, T, A, B>says, "if I have a functionA => B, I can usemodifyto obtain a functionS => T", this converts all of theAs inStoB, producing aT.Mnemonically, the type parameters of
PTraversalare:Sthe source of thePTraversalTthe "modified" source of thePTraversalAthe target of thePTraversalBthe "modified" target of thePTraversalPTraversals are useful, because they let you write things such as the following:Letting you traverse over an
Arraywhile changing the type of the elements.In your specific case, you've mentioned having two functions:
These can be composed together to produce a single function:
You'll then need to write a
PTraversal<PartialState, State, Partial<Child>, Child>.This would support composing with a
Lensto make a newPTraversalin much the same way thatTraversaldid.This should be doable, I think from your question that if you can convert every
Partial<Child>inPartialStateto aChildyou should be able to make aState.PTraversalexists in Monocle (the Scala library), but unfortunately it doesn't look like it's made it intomonocle-ts: So you would unfortunately have to write quite a lot of optics library code in order to support this.