Как мне использовать развернутый полиморфный вариант [тип объединения] в параметре типа?

#interop #ffi #reason #bucklescript #rescript

#взаимодействие #ffi #Причина #bucklescript #повторный сценарий

Вопрос:

Цель: привязка к кэшу Service Worker

Я пишу привязку, позволяющую мне писать работников службы в ReScript. Строковые URL-адреса и запросы иногда используются взаимозаменяемо.

Там, где это возможно, я избегаю шума в выводе JS.

Что я знаю о [@bs.unwrap]

Я знаю, что могу написать привязку для чего-то вроде метода add, используя [@bs.unwrap] примерно так

 [@bs.send]
  external add: (cache, [@bs.unwrap] [ `Request(Request.t) | `String(string)])
  => Js.Promise.t(unit) = "add";
 

Это простое использование.

Проблема: привязка с array помощью запросов и / или строк

Однако метод addAll имеет более сложную сигнатуру типа. Требуется массив объектов, который может быть массивом или запросами или массивом строк или массивом, который содержит элементы обоих типов.

Но, насколько я знаю, вы не можете распаковать тип внутри параметра типа, например

 [@bs.send]
  external addAll: (cache,
   array([@bs.unwrap] [ `Request(Request.t) | `String(string)])
  => Js.Promise.t(unit) = "addAll";
 

Вопрос: возможно ли такое связывание для моделирования в ReScript?

Конечно, было бы разумно просто отказаться от строкового регистра и использовать запросы или написать две отдельные привязки и предположить, что мне не понадобится массив, в котором есть оба.

Но теперь мне просто любопытно: есть ли способ смоделировать такой тип ввода в привязке в ReScript?

Ответ №1:

Вы можете использовать абстрактный тип и набор функций преобразования для «приведения» значений к этому типу вместо полиморфного варианта:

 module Value = {
  type t;
  external request: Request.t => t = "%identity";
  external str: string => t = "%identity";
};

[@bs.send]
  external addAll: (cache, array(Value.t)) => Js.Promise.t(unit) = "addAll";
 

Пример использования:

 addAll(cache, [|
  Value.request(req),
  Value.str("foo"),
|])
 

или использовать local open для краткости:

 addAll(cache, Value.[|
  request(req),
  str("foo"),
|])
 

Именно так Js.Json работают и кодировщики, если вы когда-нибудь задумывались. А поскольку Js.Json у вас тоже есть декодеры, вы знаете, что можно пойти и другим путем, если вам когда-нибудь понадобится. Однако это немного сложнее, и зависит от базовых типов, которые были абстрагированы.

Кстати, это взято из моей кулинарной книги BuckleScript, в которой также есть немало других рецептов, которые могут пригодиться в подобных сложных ситуациях.