Как преобразовать Js.Dict.t в Js.t в 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. Мы просто предполагаем, что это так.

Следовательно, единственный правильный способ преобразовать Js.Dict.t к 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
    }
Другие вопросы по тегам