Convert polyvariants to string

There can be many reasons why you’d like to convert polyvariants, maybe you’d like to pass it to React.string or you’re using them as keys to your objects. In short this is how you achieve it, with the coercion operator :>

type t = [|#dog | #cat |#"guinea-pig" ]

let toString = (pet: t) => (pet:>string)
//Check if string, if I can use string ++ operator, it's a string

Js.log("I want a " ++  #cat->toString)

And there can also be cases where you’d like to convert those strings back to polyvariants. Let’s take an example, we get a list from the backend of all the different types of car body types - also called chassis. The backend has defined some enums for this and other strings are not supposed to be used so we’d like to use polyvariants for this case.


We’re maybe displaying all those polyvars in a dropdown, or passing them into functions that only accept strings, like React.string, or god knows what. Then we sometimes need to convert string back into a polyvar, for example if our form system uses a string, we get a value from a dropdown and then we have to convert it to polyvar before sending the value to the backend. In these cases it can be handy to have some helpers functions to cast them into strings and then back into polyvars.


The syntax for fromString and toString helper functions is not so straight forward so here are some explanations


let fromString = (string: string): option<t> => {
    switch Obj.magic(string) {
    | #...t as valid => Some(valid)
    | _ => None


This is in the docs but you might have forgotten it because it’s not used so much. It’s just a shorthand so that you don’t have to type out all the possible cases yourself


Screenshot 2022-11-14 at 09.46.06 (1).png


You can see the type returned from Obj.magic is “any”


Here’s a playground link using Obj.magic. If you change the Obj.magic(”Neon”) to be a string just switch “Neon” then rescript will not compile and complains about our polyvars not being strings


So using Obj.magic is just a convenient way of not specifying the type, in this case into polyvar. If we would not use that one, we would first have to create a switch that tackles every single possible case

switch chassis {SUV” ⇒ Some(#SUV)SEDAN” ⇒ Some(#SEDAN) 
  _ ⇒  None



Polyvars actually translate to string in javascript, see this playground. Even so, we have to cast the value to a string, because it remains a polyvar inside our code before it outputs into javascript.

let toString = (chassi: t) => (chassi :> string)

:> this is called coercion operator and there’s a small section on it in rescript’s docs

You could also do it on your own but it would cost much more lines of code if you have many possible values

switch chassis {
 | #SEDAN ⇒ “SEDAN| #SUV ⇒ “SUV... etc

before we used to do something like string = "%identity"

but using the coercion operator is better because if you use it it will give you a type error if you define add something to the type like #Other(string). You might be thinking, why would we want a type error in that case ? Well, what would #Other(”hello”) become when translated to string ? Will it become “Other” or “hello” or “Other hello” ? It actually becomes an object, which doesn’t make so much sense when the name of the function is “toString”. See for yourself here and feel free to play around, you can uncomment the other toString function, and try to remove and add #Other(string) again


Get more tips in my almost monthly newsletter about CSS & React!