Void / never type in rescript?

Hi,
Sorry if the answer is somewhere in the docs but I can’t find it.
I was wondering if there’s a never / Void / Empty type (i.e without inhabitant) with rescript ?
Best,
Matthieu

@err0r500 Something that is close to void in rescript is unit type. You can check it here.

Hi @praveen ,
Thanks for your answer but I’m looking for a type that can’t be constructed Bottom type - Wikipedia

I’m surprised not to find it in the rescript type system but I guess I can live without it :slight_smile:

An abstract type without any functions that return values of that type is similar to never:

type never

let aFunctionThatCannotBeCalled = (x: never) => Js.log("Hello")

There’s no common predefined type like this that I know of, though. I think because it’s never needed in practice. Do you have a real world use case where you need it?

1 Like

yes, I like to do something like that in “business” apps :

in a shared “Error” module (used everywhere in the app) :

type never

type t<'a> = BusinessErr('a) | TechErr

type techOnly = t<never>

let f = (x: techOnly) =>
  switch x {
  | TechErr => "hello"
  }

and the compiler shouldn’t complain about a missing case in the pattern matching (but it does in rescript).

I can find workaround without problem, I’m just surprised not to be able to do that.

1 Like

If you want to constrain a type to a subset, you can use polymorphic variants in ReScript:

type t<'a> = [#BusinessErr('a) | #TechErr]

let f = (x: [#TechErr]) =>
  switch x {
  | #TechErr => "hello"
  }

Have a look at Polymorphic Variant | ReScript Language Manual.

9 Likes

The polymorphic variant answer is nice, but here is another way, in case you wanted to know how to do it in a way that’s like the uninhabited type (aka empty variant, bottom type, …).

As far as I can tell, you can’t do uninhabited types in ReScript directly (it would be something like type never = |). But you can get the same result with the GADT.

You just have to change your never type a bit.

// GADT
type rec type_equal<'a, 'b> = T: type_equal<'a, 'a>

// You can never construct a value of this type!
type never = type_equal<unit, int>

type t<'a> = Business_err('a) | Tech_err

type techOnly = t<never>

let f = (x: techOnly) =>
  switch x {
  // Compiler knows this is the only case you can have.
  | Tech_err => "hello"
  }

let x = f(Tech_err)
Js.log(x) // prints "hello"

// Won't work!
// let y = f(Business_err("whatever"))

I don’t know if doing this is worth it to you, but you could do it!

6 Likes

Great ! In my opinion, it’s totally worth it ! :slight_smile:
Thanks a lot ! (and I didn’t know that GADTs were supported by rescript, cool)

1 Like