Hegel作为JavaScript类型检查器中的新秀,励志要成为最好的JavaScript静态类型检查器。它宣称提供了一个具备强类型推断的可靠的类型系统。目前Hegel还在alpha测试阶段,大家可以在其提供的专用在线练习场进行功能体验。
Hegel是一个类型注解可选的JavaScript类型检查器,同时它和TypeScript一样,使用者不需要重新学习一门新的语言结构,只需要掌握注解的语法。Hegel希望通过强大的、稳定的类型系统,尽量避免程序在运行时由于类型错误产生的异常。下面的代码展示了其强大的类型检查能力:
// 定义numbers的类型为Array<number>
const numbers: Array<number> = [];
// 将numbers变量赋值给numbersOrStrings, 但其类型为Array<string | number>
// Hegel会检查出类型错误:
// HegelError:类型"Array<number>"和类型"Array<number | string>"不兼容
const numbersOrStrings: Array<string | number> = numbers;
// 给numbersOrStrings第二个元素赋值
numbersOrStrings[1] = "Hello, TypeError!";
// 下面的代码 Hegel会检查出类型异常:
// HegelError: 属性"toFixed"在 "Number | undefined"中不存在
numbers[1].toFixed(1);
上面的代码使用TypeScript(v3.8.3)进行编译时没有任何错误,但是在实际运行时确会抛出异常。
译者注: JS运行时,numbers和numbersOrStrings都是引用类型。他们在相互赋值的时候,属于引用赋值。因此numbersOrStrings修改元素内容的时候,对numbers也同样有效果。所以在执行numbers[1].toFixed(1)时候,就会报错,因为字符串没有toFixed函数。上面的代码体现了Hegel可靠的类型系统。
除了可靠的类型系统,健壮的类型推断也是Hegel的主要设计目标。示例代码如下:
// Hegel会推断"promisify"是"<_q, _c>((_c) => _q) => (_c) => Promise<_q>"
const promisify = fn => arg => Promise.resolve(fn(arg));
// 这里,Hegel会推断为 "<_c>(_c) => Promise<_c>"
const id = promisify(x => x)
// 同样,"upperStr"会被推断为 "Promise<string>"
const upperStr = id("It will be inferred").then(str => str.toUpperCase()
// 最后"twiceNum"将会被推断为"Promise<number>"
const twicedNum = id(42).then(num => num ** 2);
而在TypeScript(测试版本:3.7.5)中运行相同的代码时,TS会识别3个异常,同时会将变量result
推断为Promise<any>
类型。 因此健壮的类型推断允许开发人员尽量少的编写代码注释,这样反而更有利于代码的可读性。
Hegel将异常也纳入了类型检查中,示例代码如下:
function assert(age) {
if (typeof age !== "number") {
throw new TypeError("Age is not number.");
}
if (age <= 0) {
throw new ReferenceError("Age can't be less or equals zero.");
}
}
try {
assert(0);
} catch(error) {
// 这里的"error"变量,被推断为"ReferenceError | TypeError | unknown"
}
Hegel的缺点是不支持强制类型转换和any
类型,示例如下:
// Error: Hegel中不存在 any 类型
const something: any = null;
// Error: Hegel中不支持类型转换
(null: any).call();
在Hegel文档中说明了其与主流类型检查器(TypeScript和Flow)的对比。除了支持标准类型(基础类型、函数、对象、类、数组)之外,Hegel的类型系统还支持了未知类型(例如由JSON.parse()返回的类型)、可选类型、联合类型、元祖类型、类型别名、泛类型和可变类型。这也是Hegel的特性之一。 可变类型可以帮助我们从现有类型提取或者创建新类型。因此,可变类型可以理解为从一个类型生成另一个类型的函数。在Hegel中,定义了17个可变类型。
下面是可变类型$Exclude (语义上和TypeScript中的Exclude类型类似)的示例代码:
// 定义类型
type Status = "Ok" | "Failed" | "Pending" | "Canceled";
// 使用 可变类型之后
// IntermediateStatuses = "Canceled" | "Panding"
type IntermediateStatuses = $Exclude<Status, "Ok" | "Failed">;
// 赋值
const intermediateStatuses: Array<$Exclude<Status, "Ok" | "Failed">> = ["Pending", "Canceled"];
// Hegel 类型检查异常:
// Error: 类型"['Failed']"和类型"...Array<'Canceled' | 'Pending'>"不兼容
intermediateStatuses.push("Failed");
parceljs的作者,Devon Govett在Twitter上感慨说:
Hegel看上去很有趣,它比TS更接近Flow,而且是使用JS实现的。专注于类型推断和健壮类型,只有JS和类型(没有额外的功能)。支持.d.ts、vscode集成,等等…。
Hegel发布在npm上,提供了一个命令行工具和一个可交互的在线体验区。同时,其在GitHub仓库提供了对应的安装命令,要求node.js最低版本为12。
Hegel是基于MIT协议的。欢迎大家在该项目的GitHub上进行反馈和贡献。另外,Hegel的作者也声明:
Hegel源于社区,奉献社区;因此,你的任何PRs和issues都不会被忽略和遗忘。
原文链接:
https://www.infoq.com/news/2020/05/hegel-type-checking-javascript/
领取专属 10元无门槛券
私享最新 技术干货