Hi. I'm new to purescript (and fairly new to JS, too). I'm interested in writing bindings to a few JS libraries. A common design pattern I've seen in several of these JS libraries is the use of an "options" object like this { showFoo: true, fooLabel: "FOO"}
, the behaviors of which are as follows. I'll use the purescript-react
package as a basis of description, but it applies to lots of other packages.
- None or some properties of the options object are required, and some or all are optional. In the case of react,
render
is required but getInitialState
, componentWillMount
etc. are optional.
- If an optional property is not specified, a reasonable default behavior is used instead.
- The values of different properties can have different types.
- For some options, the property's value can have one of several allowed types.
PS-react handles (mostly) this scenario by defining a spec
that includes all the optional properties, and the required render
property is specified separately. The spec
defines all optional properties and gives them default values that emulate the behavior of the react pacakge when the optional properties are not specified.
Is this the canonical way to handle options? For small options objects it seems ok to me because it's reasonably easy to keep the property defaults of the bindings and the default behaviors of the package in sync. Also, redefining the same default options again and again in the generated JS isn't a big deal.
However, for some packages like dygraphs
that have an options object with dozens of properties, keeping the binding default values and the package's default behaviors in sync can be a lot harder, and generating large options objects with mostly default options specified seems wasteful.
What is the recommended approach for specifying such options to foreign library calls in purescript? Can it be done in a type-safe but general way that can be applied to all foreign libraries? If not, is there a need for such functionality, and if so, where would the right place to add it be? I was thinking something along the lines of the following, although there might be some mistakes due to my newbishness.
myOpts = opts [ getInitialState myHandler1
, componentWillMount myHandler2
] :: Options ReactOpt
opts :: [Tuple String a] -> Options a
data ReactOpt = GetInitialState Handler1Type | ComponentWillMount Handler2Type | ...
getInitialState = Tuple "getInitialState" <<< GetInitialState
componentWillMount = Tuple "componentWillMount" << ComponentWillMount
....
In this case, opts
would be a general function specialized by an ADT defining the available options. The implementation of opts
would generate a {}
object with the properties specified in the list only to prevent code inflation.
Essentially, I would like guidance from more experienced purescript practitioners on how to handle this kind of options case because I have encountered it when looking at several JS libraries to write bindings for. Thanks very much.