Рубрики
Без рубрики

Привязка к функции JavaScript, которая возвращает вариант в резкости

Rescrict предоставляет простые способы привязать к большинству функций JavaScript таким образом, что они чувствуют себя как нативными, так и … Tagged с помощью JavaScript, IndexedDB, Rescrict, функциональный.

Rescrict предоставляет простые способы связывать большинство функций JavaScript таким образом, чтобы ощущаться как нативно, так и безопасно. Удобно, он даже обеспечивает @unwrap декоратор для параметрического полиморфизма. Тем не менее, есть несколько мест, где мы все еще должны заполнить пробелы. В этой статье документируется, как привязаться к функции JavaScript, которая может вернуть любой из нескольких различных типов, используя варианты резкости.

Необходимость в пользовательском решении

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

TypeScript имеет дело с этим очень буквально через типы союзов. То есть тип буквально определяется как OneType | Theothertype так что разработчик может учитывать оба случая. Резкгрипция не имеет типов союза, но имеет Варианты , который может быть абстракциями вокруг различные виды.

Под капотом это объекты JavaScript со свойствами, которые представляют базовые значения.

Образец вывода из официальной документации

var f1 = /* Child */0;
var f2 = { 
    TAG: /* Mom */0, 
    _0: 30, 
    _1: "Jane"
};
var f3 = { 
    TAG: /* Dad */1, 
    _0: 32
};

Это гладко на стороне резкости, но ненативен к JS. Это означает, что под текущей структурой варианта нет пути, чтобы напрямую связываться с таким методом, как Idbobjectstore.keypath , который может вернуться NULL строка или массив струн. Мы, безусловно, можем представлять аналогичный тип

IdbobjectStoreKeypath.res

type t = Null | String(string) | Array(Js.Array.t);

… но Rescrict ожидает, что экземпляры такого типа будут иметь Тег и пронумерованные свойства, такие как выборочный вывод JavaScript выше. Нам нужен способ классифицировать Что возвращается нашим привязкой, и соответствующим образом называют соответствующий конструктор варианта.

Написание привязки к фиктивному типу

Мы собираемся сделать немного небезопасной черной магии, которую мы не хотим, чтобы пользователи нашей библиотеки использовали, поэтому давайте завершим его в модуль, чтобы компенсировать его из кода, который мы разоблачим в нашем .Resi :

module Private = {
};

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

module Private = { 
    type any; 
    @get external keyPath: t => any = "keyPath";
};

Теперь давайте углубимся в уродливые вещи.

Думать о типах в JavaScript

Давайте на мгновение выйдем из резкости и подумаем о стороне выполнения JavaScript. Если бы мы управляли этим в JavaScript, мы бы, вероятно, использовали бы тип Оператор для возврата строки, а затем мы сможем соответствующим образом отразить нашу логику.

Но мы не можем только использовать тип Потому что тип нуля и typeof [] Оба возвращаются "объект" , так что нам также понадобится нулевая проверка.

Так что, если бы мы делали это в JavaScript, мы получим кусок кода что -то вроде

x => x === null ? "null" : typeof x

Давайте держимся за эту мысль.

Моделирование типа типа в резкости

Наше выражение Javascript выше (для всех idbobjectStoreKeypath s) вернет «null», «объект» или «строка». Это очень хорошо переводится на полиморфический вариант резкости, например, так:

type typeName = [#null | #"object" | #"string"];

Итак, теперь, с этим типом, мы можем ввести наше выражение JavaScript в %RAW JavaScript фрагмент:

type typeName = [#null | #"object" | #"string"]; 
let getType: any => typeName = %raw(`x => x === null ? "null" : typeof x`);

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

волшебным образом называть правильный конструктор

У нас есть последний шаг: нам нужно включить наш Typename Чтобы позвонить в переключение на нашем Typename , используйте Obj.magic Чтобы преобразовать наш тип в правильный тип резкости, а затем позвонить нашему конструктору, который завершит наш тип в наш вариант.

  let classify = (v: any): IDBObjectStoreKeyPath.t => 
    switch(v -> getType) {
    | #null => IDBObjectStoreKeyPath.Null;
    | #"object" => IDBObjectStoreKeyPath.Array(v -> Obj.magic);
    | #"string" => IDBObjectStoreKeyPath.String(v -> Obj.magic);
    };

Obj.magic Будет отдать ценность, чтобы вернуть все, что он делает, но наш Переключение должен убедиться, что актерский состав безопасен (на практике, хотя и не теоретически).

классификация любого клавиатуры

Связывая все это вместе, теперь мы можем использовать наш классифицировать функция дезинфицировать любой фиктивный тип возвращен из нашего клавиатура связывание.

let keyPath = (t: t): IDBObjectStoreKeyPath.t => 
  t -> Private.keyPath -> Private.classify;

(Это та вещь, которая волнует меня по поводу функционального программирования- когда мы разбиваем вещи на достаточно маленькие кусочки, все кажется простым и простым.)

Завершая

Я надеюсь, что это был полезный ресурс для написания сложных привязков. Просто чтобы просмотреть, мы смогли успешно вернуть этот вариант …

IdbobjectStoreKeypath.res

type t = Null | String(string) | Array(Js.Array.t);

… из функции называется клавиатура Обертывая привязку, как так:

Idbobjectstore.res

type t;

module Private = {
  type any;
  @get external keyPath: t => any = "keyPath";
  type typeName = [ #null | #"object" | #"string" ];
  let getType: any => typeName = %raw(`x => x === null ? "null" : typeof x`);
  let classify = (v: any): IDBObjectStoreKeyPath.t => 
    switch(v -> getType) {
    | #null => IDBObjectStoreKeyPath.Null;
    | #"object" => IDBObjectStoreKeyPath.Array(v -> Obj.magic);
    | #"string" => IDBObjectStoreKeyPath.String(v -> Obj.magic);
    };
};

/* properties */

let keyPath = (t: t): IDBObjectStoreKeyPath.t =>
  t -> Private.keyPath -> Private.classify;

Я надеюсь, что это было полезно для моделирования типов союзов с использованием вариантов резкости. Со своей стороны, я обязательно вернусь к этой статье, продолжая писать и итерацию на привязках.

Оригинал: “https://dev.to/webbureaucrat/binding-to-a-javascript-function-that-returns-a-variant-in-rescript-im”