You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm currently designing an API to make it easier to interact with React from F# and the language combination is providing several interesting opportunities for static checking. However, as expected there are some rough ends and I have doubts about how to define the properties in a React DOM element. Currently we have:
This is the most flexible option as we can pass any property in a plain JS object. Thanks to inlining functions we don't need to use createObj here and we also save some braces. If you think the ==> is too verbose, shortening is also trivial: let inline (=>) a b = a ==> b
Now we have static checking and auto completion for the properties which is very nice. Note however that some frictions with the type definitions start to show up and need to resolved with unbox. The biggest problem with this approach is that, though the TypeScript definition uses the standard DOM elements, some attributes have a different spelling in React. In the example above, setting onchange won't work, so we have to set onChange dynamically. This almost breaks all the benefits of static checking :(
Our next option then is to use React.HTMLAttributes instead to be sure we're using the correct spelling:
R.input (fun p ->
p.``type``<- Some "text"
p.placeholder <- Some "Your name"
p.value <- unbox x.state.author
p.onChange <- unbox x.handleAuthorChange
)[]
Ok, all the properties have the spelling as React expects it but we now face other problems: first the frictions with the signature multiply because all properties are defined as optional and other Typescript custom elements are used like erased union types or custom-defined functions; and second, in the previous option we had the specific attributes for input tags but here every HTML element share the same attributes. However, this may still be the best option.
There'd be a fourth option but I'm not considering it very much:
Option 4: Using a custom HTMLAttributes record
R.input (fun p ->{ p with``type``= Some "text"
placeholder = Some "Your name"
value = unbox x.state.author
onChange = unbox x.handleAuthorChange
})[]
This one is likely the most idiomatic in F# but the indentation rules get more complicated ({ p with cannot be put in the first line) and we don't have auto completion here to discover the properties of p, as far as I know. Most importantly, adopting this style would require creating a custom record for HTMLAttributes as the ones from TypeScript are parsed as interfaces (there are good reasons for that), so this would add an extra step in the maintenance of the Fable.Import.React file.
Here are the options to make the decision and I would love to hear your say on this. I know it's possible to add several options to the API, but this would probably make it more confusing for newcomers and I'd prefer to make it simple at first. Thanks a lot for your help in advance!
The text was updated successfully, but these errors were encountered:
I'm currently designing an API to make it easier to interact with React from F# and the language combination is providing several interesting opportunities for static checking. However, as expected there are some rough ends and I have doubts about how to define the properties in a React DOM element. Currently we have:
Option 1: Dynamic properties
This is the most flexible option as we can pass any property in a plain JS object. Thanks to inlining functions we don't need to use
createObj
here and we also save some braces. If you think the==>
is too verbose, shortening is also trivial:let inline (=>) a b = a ==> b
The problem is that we don't have any static checking or auto completion for the properties. So I'm considering using a lambda instead. But now we have to decide where to get the signature from. At first I took the one from the IntrinsicElements defined in the React definition file:
Option 2: Mutating HTMLElement properties
Now we have static checking and auto completion for the properties which is very nice. Note however that some frictions with the type definitions start to show up and need to resolved with
unbox
. The biggest problem with this approach is that, though the TypeScript definition uses the standard DOM elements, some attributes have a different spelling in React. In the example above, settingonchange
won't work, so we have to setonChange
dynamically. This almost breaks all the benefits of static checking :(Our next option then is to use React.HTMLAttributes instead to be sure we're using the correct spelling:
Option 3: Mutating React.HTMLAttributes properties
Ok, all the properties have the spelling as React expects it but we now face other problems: first the frictions with the signature multiply because all properties are defined as optional and other Typescript custom elements are used like erased union types or custom-defined functions; and second, in the previous option we had the specific attributes for
input
tags but here every HTML element share the same attributes. However, this may still be the best option.There'd be a fourth option but I'm not considering it very much:
Option 4: Using a custom HTMLAttributes record
This one is likely the most idiomatic in F# but the indentation rules get more complicated (
{ p with
cannot be put in the first line) and we don't have auto completion here to discover the properties ofp
, as far as I know. Most importantly, adopting this style would require creating a custom record forHTMLAttributes
as the ones from TypeScript are parsed as interfaces (there are good reasons for that), so this would add an extra step in the maintenance of the Fable.Import.React file.Here are the options to make the decision and I would love to hear your say on this. I know it's possible to add several options to the API, but this would probably make it more confusing for newcomers and I'd prefer to make it simple at first. Thanks a lot for your help in advance!
The text was updated successfully, but these errors were encountered: