Как определить сигнатуру для хэша с атрибутами в Сорбете? - PullRequest
1 голос
/ 30 июня 2019

(обратите внимание, что это не воспроизводится на sorbet.run, насколько это возможно, его можно воспроизвести только с локальной копией Sorbet)

Я надеялся, что смогу использовать функцию Типизированные структуры , чтобы создать сигнатуру метода, где одним из параметров является хеш options, но это не работает:

# typed: true
require 'sorbet-runtime'
extend T::Sig

class OptionsStruct < T::Struct
  prop :x, Integer, default: 1
end

sig { params(options: OptionsStruct).void }
def method(options)
  puts options.x
end

# This works
method(OptionsStruct.new({x: 2}))

# This causes the typechecker to throw.
method({x: 2})

По сути, когда вы проверяете этот файл, он жалуется на передачу хэша, когда ожидается Struct. Мой вопрос: как я могу определить действительную подпись для хэша, который имеет определенные параметры? Структуры явно не работают здесь. Хотя я не пробовал Shapes, в соответствии с документами они очень ограничены, поэтому я предпочел бы не использовать их, если это возможно.

В документации об обобщениях упоминаются хэши, но, как представляется, предполагается, что они могут использоваться только в том случае, если ключи и значения хеша относятся к одним и тем же типам (например, Hash<Symbol, String> требует, чтобы все ключи были символами и все значения be Strings) и не предоставляет никакого способа (насколько я знаю) определять хеш с конкретными ключами.

Спасибо!

1 Ответ

2 голосов
/ 01 июля 2019

По сути, вы должны выбрать один из нескольких способов (три из которых вы уже упомянули):

  1. Используйте T::Hash[KeyType, ValueType].Это позволяет использовать синтаксис {} при вызове метода, который принимает его в качестве параметра, но вынуждает использовать тот же тип ключа и значения для каждой записи.
  2. Использовать T::Hash[KeyType, Object].Это немного более гибко для типа значения ... но вы теряете информацию о типе.
  3. Используйте T::Hash[KeyType, T.any(Type1, Type2, ...).Это среднее между 1 и 2.
  4. Используйте фигуры.Как говорится в документации, функциональность может измениться и быть экспериментальной.Это самый хороший способ смоделировать что-то подобное без навязывания вызывающему абоненту T::Struct:
sig { params(options: {x: Integer}).void }
def method(options)
  puts options[:x]
end
Используйте T::Struct, как и вы.Это заставляет вас вызывать метод с MyStruct.new(prop1: x, prop2: y, ...)

Все они действительны, 4 и 5 - те, которые обеспечивают вам максимальную безопасность типов.Из этих двух 4 является наиболее гибким для вызывающего абонента, но, как вы знаете, 5 Sorbet не собирается менять поддержку в краткосрочной / среднесрочной перспективе.

...