Как преобразовать Js.Dict.t в Js.t в ReScript?

#reason #bucklescript #rescript

#Причина #bucklescript #rescript

Вопрос:

Есть ли прямой способ преобразовать Js.Dict.t подобное

 Js.Dict.fromArray([
    ("bigKey", Js.Dict.fromArray([("smallKey", "value")]))
])
 

чтобы Js.t понравиться этот:

 {
    "bigKey": {
        "smallKey": "value"
    }
}
 

Ответ №1:

По структуре они уже одинаковы — оба представлены как объекты JavaScript — поэтому технически нет необходимости «конвертировать» его. Несмотря на то, что они одинаковы структурно, типы различаются взаимоисключающими способами, и поэтому нет никакого способа преобразовать один в другой в целом.

Js.Dict.t это однородная коллекция из неизвестного числа пар ключ-значение, в то время Js.t как это гетерогенная коллекция из фиксированного числа пар ключ-значение, хотя она также поддерживает подтипы и в сочетании с выводом типов может показаться динамической.

Итак, самый простой способ сделать это — просто преобразовать его в «открытый» тип объекта, который будет выведен как то, что вы хотите, чтобы это было:

 external dictToJsObject : Js.Dict.t(_) => Js.t({..}) = "%identity";
 

Но имейте в виду, что здесь нет безопасности типов для ключей. Компилятор просто предположит, что, как бы вы его ни использовали, это правильно. Если вы используете ключ, предполагается, что он существует, и ограничение типа значения из Js.Dict.t не переносится и не согласуется между ключами.

Немного лучший подход — преобразовать его в объект «закрытого» типа с известной формой:

 external dictToJsObject : Js.Dict.t('a) => Js.t({ "foo": 'a, "bar": 'a }) = "%identity";
 

Здесь указывается, что возвращаемый объект имеет ключи foo и bar имеет тот же тип значения Js.Dict.t , что и . Это обеспечивает значительно большую безопасность типов, но мы все еще не можем знать во время компиляции, что ключи foo и bar действительно существуют в Js.Dict.t . Мы просто предполагаем, что это так.

Следовательно, единственный правильный способ преобразовать a Js.Dict.t в a Js.t в целом — это сделать это вручную:

 let dictToJsObjec
  : Js.Dict.t('a) => option({"foo": 'a, "bar" 'a})
  = dict =>
    switch ((Js.Dict.get(dict, "foo"), Js.Dict.get(dict, "bar"))) {
    | (Some(foo), Some(bar)) => Some({
        "foo": foo,
        "bar": bar,
      })
    | _ => None
    }