rubysorbet

Recursive type_alias in sorbet


How would one declare a type alias that can contain a reference to itself? For example to mark a function returning a JSON-like structure.

Trying:

Foo = T.type_alias { T.any(Integer, T::Array[Foo]) }

Gives the following error:

Type alias Foo is involved in a cycle


Solution

  • As of version 0.5.x, this is not possible, as type aliases don't support cycles.

    One option is to lower the typedness of your result, and just make it:

    Foo = T.type_alias { T.any(Integer, T::Array[T.untyped]) }
    

    If you really want to have type checking, you can express something like this by wrapping the result in a T::Struct. The objects will no longer be as flat as originally, though (see in sorbet.run):

    class Foo < T::Struct
      prop :content, T.any(Integer, T::Array[Foo])
    end
    
    myFoo = Foo.new(content: 1)
    content = myFoo.content
    case content
    when Integer
      puts "It was an integer!"
      T.reveal_type(content)
    when Array
      puts "It was a Foo!"
      T.reveal_type(content)
    else
      T.absurd(content)
    end
    

    Edit (2022-02): The documentation on type_alias has been updated to address recursive definitions. It includes an example for JSON-like structures in sorbet.run.