ReScript 已经发展了很长时间,也许是时候从 TypeScript 切换到它了?
ReScript,这款“来自未来的快速、简洁、完全类型的 JavaScript”,已经存在一段时间了。“ReScript”这个名字是在2020年才正式启用的,但该项目的历史可以追溯到2016年,当时它是由Reason和BuckleScript合并而成。更名的原因在于BuckleScript的目标发生了转变,它试图创建一个融入JavaScript生态系统的语言:JavaScript是唯一的构建目标,支持JavaScript开发者期望的所有特性,例如async/await语法,以及一个易于使用的JavaScript内置函数标准库。
自从更名为 ReScript 以来,项目团队一直非常忙碌。如果你在网上搜索一下人们对 ReScript 的评价,会发现一些用户不太满意的地方,或者缺少一些 JavaScript 功能。这些问题大多已经得到解决,所以让我们来看看最近有哪些改进和功能。希望你能重新审视一下 ReScript,它或许可以成为 TypeScript 的一个强有力的替代方案。
我过去问题的来源
为了整理这份问题列表,我仔细浏览了 ReScript 官方论坛、Hacker News、Reddit 和 Twitter。我力求不遗漏任何内容,而且不仅仅关注已经解决的问题。我会指出一些尚未解决、可能仍然是部分用户痛点的问题,但希望大家能够看到这门语言在过去四年中取得的巨大进步。
在使用 ReScript 之前,我必须先理解 Reason、BuckleScript 和 OCaml。
使用 ReScript 不需要了解 Reason、BuckleScript 或 OCaml 的任何知识。
ReScript 的历史可以追溯到这些语言和工具,但如今它已发展成为一个独立的系统,可以与标准的 JS 生态系统(例如 NPM、PNPM、Yarn 或任何你想要使用的包管理器)无缝集成。它生成的 JS 代码可以被任何构建工具使用,例如 Vite、ESBuild、Webpack 等。ReScript 完全融入了 JS 生态系统,你无需了解任何其他语言、新的构建工具或新的包管理器。
如果你想深入了解 OCaml,它仍然是一门很棒的语言;而Reason作为 OCaml 的另一种语法,也依然非常流行。无论是使用 OCaml 还是 Reason,你都可以编译成本地代码,或者使用 BuckleScript 的延续版本Melange。
我应该使用 Belt.Array、Js.Array 还是 Js.Array2?
由于 ReScript 的历史根植于 OCaml 和 Reason,它也继承了这些语言的一些固有特性。这些特性本身并无不妥,但 OCaml 毕竟不是 JavaScript,它有自己独特的模式和实现方式,这些模式和方式都符合 OCaml 的语言特性。当 Reason 的目标是在保持与 OCaml 完全互操作性的同时,编译成原生代码或 JavaScript 时,试图将这些模式与 JavaScript 相匹配就显得十分繁琐。如今,ReScript 专注于 JavaScript 领域,因此它拥有一个全新的核心库,旨在让用户能够轻松上手和理解。之前的标准 JavaScript 库正在被弃用,并将很快从语言中移除,而 Belt 将发展成为一个功能更全面的实用程序库,类似于 Lodash,用户可以选择是否使用。
上述问题的答案就是直接使用Array。
let t = [1, 2, 3]->Array.map(n => n + 1)
Core 目前是一个独立的库,但计划在年底前将其直接集成到语言中。
缺少 async、await 和 Promise 会很麻烦。
asyncReScript 10.1 在 2023 年初添加了对/语法的原生支持。await我上面提到的新核心库也引入了一种简化的 Promise 使用方式。
// async/await
let fn = async () => {
try {
let result = await getData()
Console.log(result)
} catch {
| err => Console.error(err)
}
}
// Promises
let fn = () => {
getData()
->Promise.thenResolve(result => Console.log(result))
->Promise.catch(err => {
Console.error(err)
Promise.resolve()
})
}
缺乏社区类型
ReScript 早期版本中,用户必须先为大多数现有的 JS 库编写自己的绑定和类型定义才能使用它们。现在,已有数百个 NPM 包提供了绑定和文档,指导用户如何将自己喜欢的 JS 库与 ReScript 结合使用。这些绑定支持React(ReScript 编译器仍然直接提供对 React 的一流支持)、Node、Jotai、React Query、React Hook Form、AntD、Material UI、Bun、Vitest、Graphqljs等等!
甚至还有一些非常优秀的 ReScript 优先库,它们真正脱颖而出,能够充分利用 ReScript 强大的类型系统和编译器,例如rescript-relay。
/* Avatar.res */
module UserFragment = %relay(`
fragment Avatar_user on User {
firstName
lastName
avatarUrl
}
`)
@react.component
let make = (~user) => {
// this is fully typed!
let userData = UserFragment.use(user)
<img
className="avatar"
src=userData.avatarUrl
alt={
userData.firstName ++ " "
userData.lastName
}
/>
}
ReScript 还提供了强大的工具,用于将 JSON 解析为类型。以下是rescript-schema的一个示例:
@schema
type cat = {
name: string,
color: string,
}
let _ =
%raw({ name: 'fluffy', color: 'orange' })
->S.parseWith(catSchema) // catSchema is generated automatically!
->Console.log
我不明白如何使用现有的 JavaScript 库。
虽然目前已有越来越多的社区用 ReScript 编写的绑定和库,但迟早你还是需要深入研究如何编写自己的绑定。好在 ReScript 的文档非常出色,而且你可以参考众多现有的 NPM 包来获取灵感。
就在本周,我需要使用一个函数path-to-regexp,我只花了短短几分钟就创建了绑定和所需的函数。
type t = string => option<{.}>
type m = {
path: string,
params: {.}, // this means any object
}
@unboxed // @unboxed is a way to have a variant type that compiles to simple javascript without a runtime object
type isMatch =
| Yes(option<m>) // the JS for this is just an object of type m
| @as(false) No // the JS for this is just 'false'
type match = string => isMatch
@module("path-to-regexp") // this is the actual binding using the types I made above
external match: string => match = "match"
let make = url => {
let fn = match(url) // and now I can call it!
path =>
switch fn(path) {
| Yes(t) => t->Option.map(t => t.params)
| No => None
}
}
我不能有两个同名文件吗?
这一点一直没变,而且由于模块系统的工作方式,以后也不会变。对于 JavaScript 开发者来说,一开始可能会觉得有点奇怪,但在其他语言中这并不算什么。你会很快习惯的。
我为什么会选择它而不是 TypeScript?
我还有另一篇文章深入探讨了这个问题:厌倦了 TypeScript?试试 ReScript 吧!
简而言之,如果符合以下条件,您应该选择 ReScript:
- 你需要的是一个强劲、可靠的系统(不要任何类型!)
- 你需要类型,但又不想编写类型注解(编译器会自动识别!)
- 你只想使用 JavaScript 的“好部分”
- 即使你的代码库非常庞大,你也希望在 VSCode 中获得极速的编译器和快速的智能感知功能。
- 你想要像模式匹配、Option 和 Result 类型以及强大的变体类型这样令人惊叹的下一代语言特性。
还不信服?
欢迎留言!我非常乐意更详细地讨论 ReScript,并解答关于它的问题!过去四年里,我一直在几个项目中使用 ReScript,现在需要用到 TypeScript 时,切换回去真的很难。亲眼见证 ReScript 的发展和演变令人惊叹,它绝对应该被视为 TypeScript 的替代方案。
封面照片由Patrick Tomasso拍摄,来自Unsplash
文章来源:https://dev.to/jderochervlk/rescript-has-come-a-long-way-maybe-its-time-to-switch-from-typescript-29he