从 JS 转换到 ReScript
ReScript 提供了一种独特的项目转换方式,这种转换方式:
确保对你的团队成员造成最小的干扰(非常重要!)。
消除了典型的验证转换正确性与保证性能的分歧。
不强制你寻找别人编写的预制绑定库。ReScript 不需要等价于 TypeScript 的
DefinitelyTyped
东西
步骤 1:安装 ReScript
在你的项目中运行 npm install rescript --save-dev
,然后像我们在新项目中的工作流程一样,将 bsconfig.json
添加到项目根目录。接着执行 npx rescript build -w
。
步骤 2:复制粘贴整个 JS 文件
让我们转换 src/main.js
这个文件。
JSconst school = require('school');
const defaultId = 10;
function queryResult(usePayload, payload) {
if (usePayload) {
return payload.student;
} else {
return school.getStudentById(defaultId);
}
}
首先,使用 %%raw
JS 嵌入技巧,将整个文件的内容复制到新文件 src/Main.res
中:
将下面的内容添加到 bsconfig.json
:
JSON"sources": { "dir" : "src", "subdirs" : true },
在编辑器中为 src/Main.bs.js
打开一个选项卡。执行命令 diff -u src/main.js src/Main.bs.js
。除了空格以外,你应该只能看到一些极小的、微不足道的差别。你已经完成了三分之一的工作!
始终确保在每个步骤中保持打开 ReScript 输出的 .bs.js
文件,以便与现有的 JavaScript 文件进行比较。我们的编译输出与你手写的 JavaScript 非常接近;你可以通过简单地观察差异来发现转换 bug!
步骤 3:将部分内容提取到 ReScript 中
让我们将变量 defaultId
变成 ReScript 的 let 绑定:
检查输出。比较差异。代码仍然正确。那就继续前进!提取函数:
格式化代码:./node_modules/.bin/rescript format src/Main.res
。
我们得到了一个类型错误:“The record field student can't be found”。没关系!始终优先确保你代码的语法是有效的。稍后再修复类型错误。
步骤 4:添加 external
,修复类型
前面的类型错误是因为没有找到 payload
的记录声明(它应该包含 student
字段)造成的。因为我们想尽快地完成转换,让我们使用对象特性来避免类型体操:
现在这触发了下一个类型错误,即找不到 school
。让我们使用 external
来绑定这个模块:
我们匆忙地将 school
的类型变成了一个多态的 'whatever
,并通过下面的用法推断其类型。这个推断在技术上是正确的,但因为 school
的值来自 JavaScript,这有些危险。这只是我们在 external
页面中展示的互操作技巧。
总之,这个文件再次通过了类型检查器。检查 .bs.js
的输出,和原始的 .js
文件进行比较;我们现在将文件转换为了 ReScript!
现在,你可以删除原始的、手写的 main.js
文件,然后 grep 导入了 main.js
的文件,将它们修改为导入 Main.bs.js
。
(可选)步骤 5:清理
如果你喜欢更高级、类型更严格的 payload
与 school
,可以这样做:
type school
type student
type payload = {
student: student
}
@module external school: school = "school"
@send external getStudentById: (school, int) => student = "getStudentById"
let defaultId = 10
let queryResult = (usePayload, payload) => {
if usePayload {
payload.student
} else {
school->getStudentById(defaultId)
}
}
我们已经:
为
school
和student
引入了一种不透明的类型,以防止误用它们的值将 payload 声明为一个仅有
student
字段的记录将
getStudentById
声明为student
的唯一方法
检查 .bs.js
的输出是否有变化。JavaScript 代码的类型严格程度取决于你;我们建议不要将它们的类型写的太详细;有时这就像是一个无底洞,产生的回报也会越来越少,特别是要考虑到过于精细设计可能会让你的一些潜在的队友不爽。
技巧和诀窍
本着同样的想法,抑制为要转换的 JS 代码编写包装函数的冲动。使用 external
,它可以保证不会出现在输出中。并且避免尝试将 JS 的数据结构转换为 ReScript 特定的数据结构,像是变体(variant)或列表(list)。现在不是做这个的时候。
一旦你在输出中产生了额外的转换代码,你那充满怀疑的队友的心智模型可能会从“我认识这个输出”变为“这个转换引入的问题可能比解决的问题多,我们为什么要再测试一遍 ReScript 代码?”。那么你就输了。
总结
将 JS 代码作为嵌入的原生 JS 代码粘贴到一个新的 ReScript 文件中。
编译并保持输出文件打开。检查代码并与原始 JS 文件进行比较。这是免费的回归测试。
始终确保你的文件在语法上是有效的。在此之前不要担心修复类型的问题。
(滥)用对象访问来快速地完成转换。
整理类型(可选)以提高稳健性。
不要做的太过火而使你的老板与队友反感。
给你的队友展示异常熟悉的输出,自豪地表明你在转换中保留了语义与性能特征。
以更安全、更成熟的方式引入一项新技术,从而获得晋升。