lib/types/types/fixed_array.rb
# frozen_string_literal: true # https://jira.corp.stripe.com/browse/RUBYPLAT-1107 # typed: false module T::Types # Takes a list of types. Validates each item in an array using the type in the same position # in the list. class FixedArray < Base attr_reader :types def initialize(types) @types = types.map {|type| T::Utils.coerce(type)} end # @override Base def name "[#{@types.join(', ')}]" end # @override Base def valid?(obj) obj.is_a?(Array) && obj.length == @types.length && obj.zip(@types).all? {|item, type| type.valid?(item)} end # @override Base private def subtype_of_single?(other) case other when FixedArray # Properly speaking, covariance here is unsound since arrays # can be mutated, but sorbet implements covariant tuples for # ease of adoption. @types.size == other.types.size && @types.zip(other.types).all? do |t1, t2| t1.subtype_of?(t2) end else false end end # This gives us better errors, e.g.: # "Expected [String, Symbol], got [String, String]" # instead of # "Expected [String, Symbol], got Array". # # @override Base 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 end end