type rec responseType<'response> =
| JsonAsAny: responseType<'response>
This is called GADT (Generalized Algebraic Data Type). This isn’t mentioned anywhere in the documentation most probably because it is an advanced topic.
If you’re familiar with Haskell/Ocaml then it works very similar to GADT in those languages.
GADT allows you to specify the polymorphic variable for each of your constructor. First let’s look at the normal variants or sum types.
type responseType =
| JsonBool(bool)
| JsonString(string)
| JsonAny
we can then observe the type signature for each of the constructor.
JsonBool : bool => responseType
JsonString : string => responseType
JsonAny : responseType
They all return the same responseType
. What if you want to differentiate the return type?
Let’s do that.
type responseType<'response> =
| JsonBool(bool)
| JsonString(string)
| JsonAny
We added a polymorphic variable 'response
to capture the return type but it’s not being used anywhere in our constructors. (btw, this is called phantom type).
Then we can do,
let x: responseType<string> = JsonString("hello")
let y: responseType<bool> = JsonBool(true)
Both x
and y
now have a different type, but you’d have to explicitly annotate the type. Also this isn’t entirely safe.
let x: responseType<bool> = JsonString("hello") // Oh no!
What we can do is use GADT to differentiate the return type.
type rec responseType<'response> =
| JsonBool(bool) : responseType<bool>
| JsonString(string) : responseType<string>
| JsonAny : responseType<'response>
let x = JsonString("hello")
let y = JsonBool(true)
x
has type responseType<string>
and y
has type responseType<bool>
. If you do something like,
let x: responseType<bool> = JsonString("hello") // we get compile error now. Nice!
This is the reason why the code in your playground doesn’t work. You had different types,
let api = (action: action) => {
switch action {
| GetExample => {
url: "http://example.com",
typ: (ResType: Request.responseType<resForExample>),
}
| GetGoogle => {
url: "http://example.com",
typ: (ResType: Request.responseType<resForGoogle>),
}
}
}
As for JsonAny
constructor, you’d need to specify the return type because there’s still polymorphic variable 'response
.
If you want to know the use case of this, I recently wrote a blog post that uses this method here Approaches to Type Safe JS Interop Design
I hope that helps.