Search code examples
rubysorbet

Why are both sig and T.let required for Sorbet to type check?


I set my file as typed: strict, and set my initialize method to take an array of floats, but srb tc reported that I had to use a T.let assertion in the body of the method:

# typed: strict
class Point
  extend T::Sig

  sig { params(c: T::Array[Float]).returns(t::Array[Float]) }
  def initialize(c)
    @c = c
  end
end

Can’t Sorbet infer the type of @c from the signature?


Solution

  • Edit: As of 2019-12 this is no longer the case (see PR #2230). Now this code is perfectly valid (note that constructors' signatures declare void as the return type):

    # typed: strict
    class Point
      extend T::Sig
    
      sig { params(c: T::Array[Float]).void }
      def initialize(c)
        @c = c # Sorbet knows that c is a `T::Array[Float]`, so it assigns that type to @c
      end
    end
    

    Previously:

    This is a known limitation in Sorbet: "Why do I need to repeat types from the constructor?"

    TL;DR:

    [Sorbet] cannot reuse static type knowledge in order to automatically determine the type of an instance or class variable.

    It was also reported in #1666 Seemingly unnecessary type annotation of instance variables