So this probably won't lead anywhere, but I wrote the whole issue before I did some calculations and saw how it might fail, and other people may come up with clever solutions, so here goes anyway:
One (slight) annoyance I have with Feliz is constructing CSS lengths:
style.height (length.px 200)
The following is more readable, using F#'s units-of-measure syntax:
To accomplish this, we need to define all units:
// Could be auto-opened
module CssUnits =
[<Measure>] type px
[<Measure>] type em
Then, all members that now accept ICssUnit
must instead have one overload for each unit:
type style =
static member inline height(value: int<px>) =
Interop.mkStyle "height" ((unbox<string>value) + "px")
static member inline height(value: float<px>) = // ...
static member inline height(value: int<em>) = // ...
static member inline height(value: float<em>) = // ...
Since there are 32 different length
members (including auto
, which I don't have a good solution for), each style
members that now has a single overload that accepts a single ICssUnit
instead gets 32 overloads each, one per unit.
It should be fairly easy to write a generator for this, where you just have a list of units and partial member definitions, and generate all members/overloads from this.
Unfortunately, one big problem is the combinatorial effects of multi-parameter functions, such as style.margin(top, right, bottom, left)
. If we want to have all possible combinations of units, this method alone gets 1,048,576 overloads just from the unit combinations. That's of course completely out of the question. I don't know if there is a solution to that, other than requiring every parameter to be the same unit, making it linear, not polynomial.
One could of course have an intermediary helper function convert from any unit to the existing ICssUnit
, e.g. style.height (length.parse 200<px>)
, but then we're back to scratch with the only difference that the unit is after the number (good) and it's more verbose and less discoverable (bad).
Feel free to just close this if you want.
PS: A question that pops to mind is what the length
type and the ICssUnit
actually accomplishes. If length.px 200
just converts to the string "200px"
, why not just write "200px"
in the first place? What additional safety does the length
type provide? (I mean, sure, it stops you from passing invalid strings like "foo"
or "200invalid"
, but I can't imagine that will ever be a problem in practice.)