
TypeScript 和 ReasonML 都宣称自己为 Web 开发人员提供了可编译为 JavaScript 的静态类型语言,那么它们之间的差别是什么?ReasonML 能带来 TypeScript 想要做到的一切(甚至更多),但是前者没有那些 JavaScript 怪癖。这样的话,你能否应该试试它呢???
TypeScript 是 JavaScript 的超集,这既是它的最佳特性,也是它最大的缺陷。虽说与 JavaScript 的类似性给了人熟习的感觉,但这意味着我们所喜爱和反感的所有 JavaScript 怪癖都在 TypeScript 里重现了。TS 只不过是在 JavaScript 之上增加了类型,而后就差不多完事了。
ReasonML 提供的是一种完全不同但让人感觉很熟习的语言。这能否意味着JavaScript /TypeScript 开发人员会很难学习这个新语言?我们就来看看吧。
公告一个变量
让我们从变量公告开始:
ReasonML
leta =?"Hi";
TypeScript
consta =?"Hi"
在 ReasonML 中,我们使用 let 关键字公告一个变量。没有 const,默认情况下 let 是不可变的。
在这种情况下,两种语言都可以推断出 a 的类型。
? ?函数? ?
TypeScript
letsum = (a:number,?b:number) =>?a+?b
ReasonML
let sum =?(a,b)=>a + b;
虽然我没有手动编写任何类型,但这个函数的参数还是类型化了。为什么我们用不着在 ReasonML 中编写类型呢?由于强大的类型系统可以进行出色的类型推断。这意味着编译器可以在不需要你帮助的情况下推断出类型。ReasonML 中的 (+) 运算符仅适用于整数——a 和 b 只能是这种类型,因而我们不必编写它们。但假如需要,你随时都可以编写类型:
ReasonML
let sum =?(a: int, b: int)=>a + b;
接口,记录?
TypeScript
interfaceProduct {
name:?string
id:?number
}
ReasonML 中最接近接口(Interface)的是记录(Record,https://reasonml.github.io/docs/en/record)。
ReasonML
typeproduct = {
name:?string,
id:?int,
};
记录就像 TypeScript 对象一样,但前者是不可变的,固定的,并且类型更严格。下面我们在某些函数中使用定义的结构:
ReasonML
letformatName =?product=>"Name: "++product.name;
TypeScript
const formatName =?(product: Product)=>"Name: "+ product.name
同样,我们不需要注释类型!在这个函数中我们有一个参数 product,其属性 name 为字符串类型。ReasonML 编译器可以根据使用情况猜测该变量的类型。由于只有 product 这个类型具备字符串类型的 name 属性,编译器会自动推断出它的类型。
升级记录

ReasonML 支持开展运算符,并像 TypeScript 一样对名称和值做类型双关。
看看 ReasonML 生成了什么样的 JavaScript 吧,这也很有趣:
Reducer 示例
我认为这就是 ReasonML 真正闪耀的地方。我们来比较一下相同的 Reducer 实现:
在 TypeScript 中(遵循这份指南:https://redux.js.org/recipes/usage-with-typescript)


没什么特别的,我们公告了状态界面、默认状态、动作、动作创立者以及最后的 Reducer。
在 ReasonML 中也是一样:

对,就这些。
让我们看看这里发生了什么。
首先,有一个状态类型公告。
之后是动作 Variant(https://blog.dubenko.dev/typescript-vs-reason/#https://reasonml.github.io/docs/en/variant)类型:

这意味着具备类型 action 的任何变量都可以具备以下值之一:Reset、带有少量字符串值的 AddMovie 和带有少量字符串值的 RemoveMovie。
ReasonML 中的 Variant 是一项非常强大的功能,可让我们以非常简洁的方式定义可以包含值 A 或者 B 的类型。是的,TypeScript 有联合类型,但它没有深入集成到语言中,由于 TypeScript 的类型是给 JavaScript 打的补丁;而 Variant 是 ReasonML 语言的重要组成部分,并且与模式匹配等其余语言功能紧密相连。
说到模式匹配,我们来看一下 Reducer。

我们在这里看到的是一个函数,该函数接受状态作为第一个参数,而后将第二个参数与可能的值匹配。
我们也可以这样写这个函数:

因为匹配参数是 ReasonML 中的常见模式,因而这类函数以较短的格式编写,如前面的代码片段中所示。{ movies: [movie, ...state.movies] }这部分看起来与 TypeScript 中的一样,但是这里发生的事情并不相同!在 ReasonML 中,[1,2,3] 不是数组,而是不可变的列表。可以想象它是在语言本身内置的 Immutable.js。在这一部分中我们利用了一个事实,即 Append 操作在 ReasonML 列表中的时间是恒定的!假如你之前用的是 JavaScript 或者 TypeScript,你可能会随手写下这种代码,无需太多顾虑,并且可以免费取得性能提升。
现在,让我们看看向 Reducer 增加新动作的操作。在 TypeScript 中是怎样做的呢?首先你要在类型定义中增加一个新动作,而后以动作创立者的形式编写少量样板,当然不要忘了在 Reducer 中实际解决这种情况,一般这一步都容易被忽略。
在 ReasonML 中,第一步是完全相同的,但是后面就都不一样了。在将新动作增加到类型定义后单击保存时,编译器会带你在代码库中慢慢挪动,解决对应的情况。
你会看到这样的警告:

这是很好的开发体验。它会指出你要解决新动作确实切位置,并且还会精确告诉你缺少哪种情况。
Null、undefined vs Option
在 TypeScript 中我们需要承受 JavaScript 留下来的负担,也就是用 null 和 undefined 来表示几乎一模一样的事物——毫无意义。
在 ReasonML 中没有这种东西,只有 Option 类型。大家在入门学习前台的过程当中有遇见任何关于学习,行业方面的问题,都可以申请加入我的前台学习扣扣裙,282549184。缺乏相关的基础教程也可以直接来找我要,我这里整理了一套最新的前台基础教程,学习前台的这个过程当中我也收集了很多前台学习手册,面试题,开发工具,PDF文档书籍教程,可以直接分享给你们。
ReasonML

这是一个大家很熟习的 Variant 类型。但是它也有一个类型参数'a。这很像其余语言中的泛型,比方说 Option。
来比照更多的代码看看:

访问可以为空的属性是最简单的情况之一,闭着眼也能写出来。在 TypeScript 中,我们可以启用严格的 null 检查而后手动检查 undefined 的值来纠正它。

在 ReasonML 中,我们可以使用内置的 option 类型和 Belt 标准库中的辅助函数,而后就能以标准化方式解决可能为空的值。
带标签的参数
我觉得所有人都会认为带标签的参数功能真是太棒了。可能每个人都必需在某个时候查询函数参数的顺序或者含义。不幸的是,TypeScript 中没有带标签的参数。
TypeScript

在 ReasonML 中,你在参数名称前加一个~ 字符,而后它就被标记了。
ReasonML

是的,你可以在 TypeScript 中尝试使用对象作为参数来模拟这种做法,但是随后你需要在每个函数调用时分配一个对象 :/
TypeScript
关于 ReasonML 的内容并不是都那么美好。它是一种相当新的语言……嗯,实际上它不是基于 OCaml 的,后者已经相当老了;但重点在于互联网上的资源依然不是特别多。与 ReasonML 相比,用谷歌搜索 TypeScript 的问题更容易取得答案。DefinitelyTyped 类型实在太多了,ReasonML 想要追上来还有很长的路要走。