вступление

Frontend-разработка - это оживленное место, в котором появляется и исчезает множество новых технологий. За последнее десятилетие мы стали свидетелями определенных сдвигов в способах разработки веб-страниц. Нам больше не нужно напрямую касаться DOM API или экспериментировать с неудобной инъекцией зависимостей Angular. В настоящее время мы активно используем различные инструменты сборки для включения ресурсов в наш код, обработки CSS и т. Д.

Мы создаем приложения FE из десятков файлов и используем бандлеры для создания производственного кода для нас. Это заставляет нас компилировать нашу кодовую базу в конечном продукте, и это очень похоже на то, что делают типизированные языки. Но есть одно большое различие: мы используем JavaScript, сверхгибкий, но очень подверженный ошибкам язык без каких-либо типов. При компиляции файлов (или, скорее, объединении и переносе для TypeScript) ничто не мешает нам заменить JavaScript чем-то, что может создавать JavaScript.

На рынке есть много идей о том, как реализовать систему типов для разработки внешнего интерфейса. Приведу лишь некоторые из них:

TypeScript, ClojureScript, PureScript, Scala.JS, Elm, JS_of_ocaml, ReScript или даже написать интерфейс на C или Rust благодаря привязкам WebAssembly и JS (например, wasm-bindgen).

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

TL; DR;

Отсутствие системы типов в JavaScript делает его отличным инструментом для быстрого прототипирования. В то же время отсутствие типов подвергает каждое изменение риску нарушения кода во время выполнения. Более обширная кодовая база увеличит масштаб ошибки, что плохо скажется на обслуживании и времени выхода на рынок. Строго типизированный язык, такой как ReScript, помогает решить эти проблемы, что может положительно повлиять на бизнес и сделать разработку более гладкой.

Кроме того, ReScript:

  • компилируется очень быстро
  • имеет устранение мертвого кода - меньший размер производственного пакета
  • Имеет синтаксис, который легко понять разработчикам JS.
  • легко реализовать в существующем проекте и интегрируется с кодовой базой JS
  • имеет функциональные особенности, облегчающие разработку

Возможности ReScript, которые помогают разработчикам создавать более плавный код:

  • операторы труб
  • каррирование по умолчанию
  • типы вариантов, которые могут нести значение и сопоставление с образцом
  • все выражение
  • неизменяемые структуры данных по умолчанию (кроме массивов)
  • модули (над объектами)

Из минусов:

  • Форматирование кода ReScript - довольно неприятный опыт, который затрудняет чтение кода (надеюсь, это может измениться в будущем).
  • Некоторые замечательные функции из ReasonML больше не действуют в ReScript (например, функция с одним аргументом fun или устаревшие каналы)
  • Для ReScript нет аналога Redux. Создание нескольких магазинов, нескольких субприложений, строго типизированного программного обеспечения требует значительного объема работы.
  • Не совсем подходит, если проект требует готовой поддержки многих библиотек со сложными API.

Преимущества Shiny Rescript

# 1 Более безопасная разработка с защитой системы типов

В первые годы работы в качестве разработчика JavaScript я не понимал необходимости выявлять ошибки во время компиляции. Создание приложения JavaScript происходит довольно быстро, особенно при горячей замене модулей. Разработчик может практически сразу вручную проверить результаты в браузере. Есть несколько инструментов разработчика для отслеживания ошибок во время выполнения JavaScript. По мере того, как приложение становится более обширным, путь к обнаружению ошибок становится длиннее, а отловить их становится все труднее и труднее.

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

Система типов TypeScript в некотором роде решает эти проблемы. Однако решить их не обещает. Я писал TypeScript уже несколько лет и был убежден, что лучше иметь какую-то систему типов, чем ее вообще не иметь. Так было до тех пор, пока я не овладел языком Rust. Rust - это язык с очень строгой типизацией, поэтому вы почти на 100% уверены, что он будет работать, если код компилируется. TypeScript далек от этого, поэтому я хотел, чтобы интерфейс был похож на Rust. Я нашел ReScript (тогда ReasonML) и решил, что лучше иметь хорошую систему типов, чем просто any.

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

Я собираюсь вкратце сравнить ReScript и TypeScript вместо JavaScript, потому что

  1. В JavaScript нет системы статических типов.
  2. TypeScript - это самый широко используемый типизированный язык для интерфейса на данный момент.

Наиболее существенные преимущества ReScript перед TypeScript:

Есть только один способ определить эквивалент объекта с помощью записи

type test = {
    name: string
}

и несколько потенциальных способов в TypeScript:

type Test = {
    name: string
};
interface Test2 {
    name: string
}
class Test3 {
    name: string;
    constructor(value: string){
        this.name = value;
    }
}

Вы должны использовать 3 из них в разных ситуациях. Но TS создан, чтобы разрешить их все, что немного сбивает с толку.

Кроме того, типы предназначены не только для компилятора. Они также предназначены для документирования кода. С помощью TypeScript создание абстракции может привести к потере проверки типа на сайте определения, в то же время получая его по вызову. Это дает компилятору гарантии, но может быть менее наглядным и более запутанным при отладке. Без явной передачи типов и использования всех трех приведенных выше примеров может потребоваться некоторое усилие, чтобы понять, какой тип на самом деле используется.

В ReScript все имеет свой тип

Все переменные, записи, функции и даже модули имеют тип в ReScript. Это означает, что компилятор всегда сообщает вам, когда вы пытаетесь передать что-то, что не подходит. В TypeScript, напротив, есть нечто под названием any, что лишает смысла всю суть системы типов. Новички в TypeScript часто злоупотребляют any, когда интерфейс не соответствует текущим требованиям. Это снижает защиту компилятора и сигнализирует о том, что может быть что-то не так со структурой кода, если реализация типа слишком сложна.

Можно настроить TypeScript так, чтобы он не принимал any, но сам tsconfig позволяет только отключить неявное использование. Вам понадобится конфигурация линтера, чтобы запретить any. Но это приведет к ошибке другого типа (ошибка линтинга вместо ошибки компилятора) и не позволит реализовать абстракцию на каком-то уровне.

В ReScript нет null или undefined

Система шрифтов не решает всех проблем. Он не исправит логические ошибки в нашем коде, но в некоторых случаях может помочь с ними. Null и undefined часто могут проникнуть в код JavaScript и вызвать неожиданное поведение. TypeScript тоже не решает проблемы. ReScript, напротив, не допускает неопределенных или нулевых значений. Всегда должен быть правильный тип. В ситуациях, когда значение может отсутствовать или какое-то выражение может возвращать ошибку, ReScript использует вариантные типы. Обычно option (Haskell Maybe) & result несут значение, информацию об его отсутствии или ошибке. Более того, компилятор ReScript заставит нас закрывать негативные сценарии.

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

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

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

Вывод высшего типа

TypeScript действительно имеет вывод типа, но, выделяя предыдущие моменты, наличие any, undefined, & null разработчиков часто должно быть явным в объявлении типа.

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

Напротив, компилятор ReScript отлично справляется с выводом типов и делает это в большинстве случаев. Это означает меньше мест для объявления типов. Это означает меньше шаблонного кода, что означает более приятную разработку. Все это по-прежнему находится в рамках охраны компилятора.

Все это может показаться не таким уж большим, но на практике все вместе они имеют огромное значение. В то время как TypeScript пытается очаровать разработчиков системами типов, ReScript заставляет типы и защищает пользователей от множества ошибок времени выполнения. Без применения any и типов это мысленный переход для разработчиков JavaScript к «разработке на основе типов».

# 2 Быстрое время компиляции и устранение мертвого кода

TypeScript 3 становится быстрее, но все еще отстает от ReScript. Компиляция ReScript выполняется быстро. Для баз кода малого и среднего размера это обычно вопрос миллисекунд. Для обширных приложений это может занять секунды, но компилятор почти сразу отвечает успехом или ошибками.

Я должен упомянуть, что вывод ReScript не является нашим производственным пакетом. Компилятор ReScript возвращает файлы JavaScript, соответствующие исходным. Это означает, что нам все еще нужно связать вывод ReScript с таким инструментом, как Webpack.

К счастью, наш вывод представляет собой легко читаемые файлы JS без JSX. Это ускоряет сборку и делает ненужным перевод JSX. На практике Webpack Dev Server с горячей заменой модуля перезагружает веб-страницу так быстро, что это может даже остаться незамеченным при переключении между приложениями или рабочими пространствами.

Выходные файлы JavaScript также очищаются от неиспользуемого кода.

# 3 Легко реализовать в существующем проекте

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

  1. При работе с ReScript вы, скорее всего, будете работать с ReScript-react. Это не новый фреймворк. Вместо этого он предоставляет привязки для React, и, как я упоминал ранее, ReScript выведет вам .res компонентов в .JS версии. Это означает, что вы можете использовать одну среду выполнения React в производственном пакете.
  2. Вы можете использовать библиотеку genType для вывода типов ReScript в типы TypeScript или использовать типы TS в своем коде.
  3. Благодаря привязкам ReScript относительно легко использовать существующую кодовую базу JavaScript и TypeScript. Также легко обернуть существующие JS-библиотеки привязками ReScript.
  4. Благодаря привязкам и выходным данным JavaScript можно легко использовать такие инструменты, как webpack, для управления препроцессорами стилей или загрузчиками ресурсов.
  5. Синтаксис ReScript очень похож на синтаксис JavaScript и должен быть очень легким для понимания разработчиками JS.

# 4 Более простая разработка с функциональным вкусом

Вы, вероятно, ассоциируете «функциональное программирование» с чистыми функциями, управлением побочными эффектами, декларативным программированием, функторами, монадами и т.д. курсы scala и др.). Кроме того, я не хочу убеждать вас в чисто функциональной разработке. Я просто хочу подчеркнуть, как практический вкус ReScript по сравнению с языками с чисто функциональным программированием может положительно повлиять на разработку.

TypeScript не является функциональным языком. Фактически, это почти как утка напечатала Java для браузера. Это не мешает вам реализовывать функциональные возможности, но значительно усложняет задачу, что приводит к усложнению кода и чрезмерной разработке. Это усложняет задачу, а функциональное программирование должно упростить задачу!

Более того, вы можете попробовать реализовать монаду Maybe (вариант ReScript) или использовать неудобные типы объединения, ввести каррирование или принудительную неизменяемость с помощью библиотек. Но все же синтаксис TypeScript / JavaScript будет вашим врагом.

Для меня функциональное программирование - это поток данных, а не то, какие переменные или объекты объявлять.

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

Оператор трубы

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

Без оператора трубы есть 3 варианта:

1. Назначьте каждое возвращаемое значение переменной:

let res1 = run1(value);
let res2 = run2(res1);

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

2. Завершить выполнение функции выполнением другой функции:

run4(run3(run2(run1(value))));

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

3. Возврат объекта с помощью методов:

class Obj1 {
    value: number;
    constructor(value: number) {
        this.value = value;
    };
    public addOne() {return this.value + 1};
};
class Obj2 {
    static multiplyByTwo(value: number) {return new Obj1(value * 2)}
};
Obj2.multiplyByTwo(2).addOne();

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

Во-первых, это требует определения структуры, которую мы хотим вернуть (obj1 в нашем примере). Это означает, что мы не можем сосредоточиться на функции. Нам нужна сразу вся цепочка.

Во-вторых, не совсем очевидно, что возвращает multiplyByTwo, пока мы не изучим определение Obj1.

В-третьих, используя значение this, мы не используем чистые функции, потому что мы используем контекст объекта, который может измениться, и мы можем изменить его, изменяя свойство объекта. Это область для множества потенциальных ошибок и серьезной отладки.

С оператором трубы:

value
    -> MathOperation.multiplyByTwo
    -> MathOperation.addOne

Это делает вещи более управляемыми. Функции просты и понятны. Кроме того, порядок выполнения интуитивно понятен. Благодаря квалифицированному импорту (путем импорта и использования всего модуля «MathOperation» вместо функций multiplyByTwo и addOne) становится ясно, какие функции являются исходными и связаны с ними.

К сожалению, после ребрендинга с ReasonML на ReScript основная группа решила отказаться от использования треугольника |> и использовать только ->.

|> передает наше значение в качестве последнего аргумента, а -> - в качестве первого. Проблема в том, что синтаксис ->, на мой взгляд, немного неудачен, поскольку стрелка также используется во многих языках для описания аннотации типов.

Карри по умолчанию

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

Простой пример:

let add = (a,b) => a + b;
add(2,2); // returns 4
let addTwo = add(2); // function that adds 2 to passed argument
addTwo(3); // returns 5

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

Допустим, у нас есть:

  • список элементов, для простоты это будет список строк
  • переменная, которая хранит выбранный кусок, строка в нашем примере

Мы хотим сопоставить список с компонентами React и выделить выбранные.

Первый:

Функция для проверки, выбран ли элемент, и добавления класса css, если он:

let selectedOrNot = (value, isSelected) => 
    isSelected == value 
        ? <p className="selected">{React.string(value)}</p>
        : <p>{React.string(value)}</p>;

а в JSX мы можем:

<div>
    {
        ourList
            -> List.map(selectedOrNot(selectedValue))
            -> ReScriptReact.list;
    }
</div>

Благодаря каррированию мы использовали значение captured в закрытии каждый раз, когда List.map запускает обратный вызов для элементов списка.

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

Типы вариантов и сопоставление с образцом

Впервые я столкнулся с подобной структурой в Rust с ее enum. Однажды узнав, трудно без этого жить. Типы вариантов полезны в нескольких ситуациях. Как упоминалось ранее, option и result помогают типизированным образом работать с несуществующими значениями или ошибками. Типы вариантов могут быть частью определения настраиваемых ошибок, которые позже могут быть использованы в качестве параметра второго типа для result:

type inputError = 
    | BadInputType
    | EmptyInput
    | ParsingError(string);

Тогда тип результата может иметь интерфейс: result ‹string, inputError›.

Необъяснимо, но большинство онлайн-руководств по Redux + TypeScript используют что-то вроде этого для описания действий и редукторов:

const MY_MAGIC_STRING_TYPE = "MY_MAGIC_STRING_TYPE";
cosnt exampleAction = value => ({type: MY_MAGIC_STRING_TYPE, value});
const reducer = (state, action) => {
    switch (action.type) {
        case: MY_MAGIC_STRING_TYPE:
        ... 
    }
}

Этот подход подвержен ошибкам. Строки - не лучшее решение для описания типов действий.

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

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

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

С TypeScript:

interface Login {
    type: "Login",
    value: string	
}
interface Logout {
    type: "Logout"
}
type SignIn = Login | Logout | null;

С ReScript:

type login =
  | Login(option<string>)
  | Logout;

Это полное определение нашего действия. Мы хотим войти в систему и запомнить имя пользователя в состоянии и выйти из системы. Нам не нужна обертка вокруг наших действий. Более того, компилятор ReScript будет жаловаться, если мы попытаемся сопоставить действие в предложении switch, не охватывая все случаи. У нас есть строго типизированное действие и компилятор, который помогает создавать редуктор.

Этим мы можем описать простой редуктор:

let reducer = (state, action) =>
    switch action {
        | Login(Some(name)) => {name} // assuming name is option(string) type
        | Login(None) => {name: “No user”}
        | Logout => {name: “No user”}
    }

Если вы не укажете кнопку входа или выхода из системы, появится предупреждение.

К сожалению, сопоставление с образцом ReScript по умолчанию не является исчерпывающим. Будет выдано предупреждение, если мы не рассмотрим все случаи. Это можно изменить, но это потребует дополнительной настройки. Это изменение гарантирует, что мы охватим все вероятные сценарии в нашем редукторе, сделав наше приложение более надежным и легким для развития в будущем.

Все является выражением

Одна из очень раздражающих ситуаций в JavaScript и TypeScript - это присвоение переменной результата блока кода.

Допустим, мы хотим присвоить результат блока if / else переменной.

В JS или TS нам нужно будет сделать что-то вроде этого:

let value;
if (condition === expectation) {
    value = 1
} else {
    value = 2
}

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

Напротив, это код ReScript:

let value = if condition === expectation {
    1
} else {
     2
}

примечание 1: let в ReScript объявляет неизменяемую переменную

примечание 2: в коде блока ReScript возвращается его последнее выражение. Если вы вернете nothing, вы все равно вернете тип единицы (), а в возвращаемом типе будет слишком много «if / if else / else».

В ReScript все является выражением, поэтому вы можете назначить, переключают ли блоки блоки или даже любой блок. Например:

let value = {
    2 * 2
}

Неизменяемые данные

Неизменяемые данные - одна из важнейших концепций функционального программирования.

В императивном программировании это может показаться мистификацией (вам нужно каким-то образом присвоить значение из блоков if / else, не так ли?). Это может показаться ограничивающим с точки зрения отдельного блока кода, но приложения обычно создаются из многих фрагментов кода.

Обычно мы берем наши данные и передаем их нескольким функциям и методам.

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

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

Кроме того, в JS и TS вы можете объявлять переменные с помощью let, const & var. Опять непонятно.

В ReScript вы просто используете let и объявляете неизменяемое значение по умолчанию (кроме массива). Вы также можете определить изменяемые поля в записях, но вам придется сделать это явно.

В большинстве случаев вам следует создать новое значение из старого, вернув новое с измененными данными.

# 6 Модули над объектами

Вероятно, это одно из самых заметных различий между ReScript и миром JavaScript / TypeScript. В JavaScript и TypeScript это типичный шаблон для построения методов на основе объектов и цепочки наследования. Хотя объекты и методы приемлемы, наследование может легко привести к длинной, трудно поддающейся отладке цепочке классов / объектов.

В ReScript нет прямого эквивалента объекта, методов объекта и наследования. Вместо этого вся функциональность должна быть построена вокруг модуля.

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

Этот подход может быть знаком разработчикам, пришедшим с таких языков, как Haskell или Elm, и сбивать с толку разработчиков Java или TypeScript.

Трудности в ReScript

# 1 Форматирование кода

Это то, что может поразить вас очень быстро, особенно если вы потратите время на настройку линтеров и красивее, чтобы получить достойный макет кода вашего компонента. Или если вы привыкли к языкам с сильными средствами форматирования, таким как Elm или Rust.

Короче говоря, форматтер ReScript не настраивается. Он обеспечивает соблюдение стиля кода, включая длину строки. Это означает, что ваш код будет переведен в одну строку, если список каналов или свойств в компонентах будет слишком коротким.

Это не только раздражает, но во многих случаях может затруднить чтение кода.

# 2 Это не ReasonML

Если вы знакомы с ReasonML, ReScript может стать для вас неприятным сюрпризом. Хотя все инструменты вместе могут быть хорошими (ReScript + BuckleScript), есть несколько хитростей. Некоторый синтаксис больше недействителен (например, fun сокращение для унарной функции сопоставления с образцом), он устарел, например, треугольник |>. ReScript также больше не поддерживает полную синхронизацию с Ocaml, превращаясь в отдельный язык. Это может не иметь большого значения для новичков, но также привлекло внимание разработчиков OCaml. Он также может быть не полностью совместим с инструментами проекта ReasonML (как, например, автор статьи Создание кодовой базы Ahrefs с помощью Melange.

Хуже всего, наверное, ситуация после «ребрендинга» на ReScript. Не все были в восторге от этого, и, поскольку неизвестно, будет ли BuckleScript все еще разрабатываться, похоже, что ReasonML не совсем мертв. Существует также вилка ReScript, которая фокусируется на совместимости с OCaml, и некоторые разработчики возвращаются к JS_of_ocaml.

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

# 3 Нет альтернативы Redux

Для ReasonML был проект Reductive. Но это все еще не такой опыт, как Redux. Сильная система статических типов усложняет разработку обширных приложений. С JS очень удобно комбинировать несколько редукторов. С ReScript и отсутствием библиотек он требует написания большого количества абстракции для комфортной работы с монорепозиторием и несколькими микроприложениями, которые должны работать как по отдельности, так и все вместе.

# 4 Не лучший вариант в качестве доказательства концепции, основанной на библиотеках JavaScript.

В ReScript улучшен синтаксис для привязок JS по сравнению с ReasonML. Основным инструментом для фронтенд-разработки является React (связывание React с ReScriptReact), и большинство библиотек его хорошо поддерживают. Учитывая все это, может потребоваться время для написания привязок для сложного библиотечного API.

Например, написать привязки для нескольких типов и компонентов React из библиотеки Recharts может быть легко, но оборачивать привязки для d3.JS может быть сложно.

Подвести итог

Работа с ReScript может быть освежающим опытом после обновления API с помощью безтипового JavaScript или исправления кода с типом any, введенного младшим разработчиком в вашей команде. Это также может быть хорошим шагом к более функциональному коду, предназначенному для интерфейса.

К сожалению, ReScript все еще молодая технология, и такие вещи, как отсутствие библиотек / привязок или проблемы с форматером, могут быть серьезными недостатками. С другой стороны, после грубого старта (ребрендинга) ReScript становится все лучше и лучше. За последние полгода документация ReScript значительно улучшилась, став прочным местом для новичков.

Итак, стоит ли вам выбрать ReScript для своего следующего проекта? Я думаю, это действительно зависит от потребностей вашего проекта.

Мои простые практические правила при выборе ReScript

Когда НЕ НУЖНО ВЫБРАТЬ ReScript

Возможно, это не лучший выбор, если вы:

  • хотите чисто функциональный опыт и не полагайтесь на библиотеки JavaScript, я рекомендую поискать Elm.
  • в основном зависят от объектно-ориентированного программирования. Вам следует выбрать TypeScript.
  • пришли из экосистемы OCaml и строго связаны с ней.
  • необходимо создать прототип решения JavaScript на основе существующей библиотеки со сложным API

Когда ВЫБРАТЬ ReScript

Это может быть хорошим выбором, если вы:

  • хотите функционального опыта и сильно полагайтесь на библиотеки JavaScript.
  • хотят придерживаться обширной экосистемы React и широко используемых инструментов, таких как Webpack или CRA, и иметь лучшие гарантии типов и более функциональный код, чем TypeScript.
  • использовать React Native
  • пришли из экосистемы OCaml, но слабо связаны с ней. ReScript может быть лучшим выбором, чем JS_of_ocaml, поскольку он ориентирован на типичную разработку внешнего интерфейса, которая отличается от внутреннего потока и инструментов.