class T::Types::FixedArray

in the list.
Takes a list of types. Validates each item in an array using the type in the same position

def describe_obj(obj)

@override Base

"Expected [String, Symbol], got Array".
instead of
"Expected [String, Symbol], got [String, String]"
This gives us better errors, e.g.:
def describe_obj(obj)
  if obj.is_a?(Array)
    if obj.length == @types.length
      item_classes = obj.map(&:class).join(', ')
      "type [#{item_classes}]"
    else
      "array of size #{obj.length}"
    end
  else
    super
  end
end

def initialize(types)

def initialize(types)
  @types = types.map {|type| T::Utils.coerce(type)}
end

def name

@override Base
def name
  "[#{@types.join(', ')}]"
end

def subtype_of_single?(other)

@override Base
def subtype_of_single?(other)
ther
ixedArray
operly speaking, covariance here is unsound since arrays
n be mutated, but sorbet implements covariant tuples for
se of adoption.
es.size == other.types.size && @types.zip(other.types).all? do |t1, t2|
.subtype_of?(t2)
e

def valid?(obj)

@override Base
def valid?(obj)
  obj.is_a?(Array) && obj.length == @types.length &&
    obj.zip(@types).all? {|item, type| type.valid?(item)}
end