ericsssan/ez-checker
GitHub: ericsssan/ez-checker
ez-checker 是一个用 Zig 编写的独立 TypeScript 类型检查引擎,提供表达式推断、类型解析、控制流窄化和跨文件解析能力,可供 linter、编译器或语言服务器等工具嵌入使用。
Stars: 1 | Forks: 0
# ez-checker
[](https://github.com/ericsssan/ez-checker/actions/workflows/ci.yml)
[](#conformance)
[](#conformance)
TypeScript 类型检查器的重新实现。仅包含类型系统:推断任何表达式的类型,解析声明,通过控制流进行类型窄化。无代码生成,无诊断信息,无 `tsconfig.json`。
最初提取自 [Ez](https://github.com/ericsssan/Ez) linter,但其类型推断引擎是通用的——可供 linter、编译器、语言服务器或任何需要对 TypeScript 类型进行推理的工具使用。
基于 [es-parser](https://github.com/ericsssan/es-parser) 构建。使用 Zig 编写。
## 已实现的功能
**表达式推断**
字面量、模板字面量、数组、对象、函数、类、二元/一元运算符、三元运算符、赋值、await、逗号表达式、类型断言(`as`、`satisfies`、`!`)。
**类型解析**
原始类型、数组、元组、联合类型、交叉类型、对象类型、函数类型、`typeof`、`keyof`、索引访问(`T[K]`)、映射类型、条件类型(包含 `infer`)、模板字面量类型、泛型类型引用、递归类型别名。
**实用工具类型**
`Partial`、`Required`、`Readonly`、`Pick`、`Omit`、`Exclude`、`Extract`、`NonNullable`、`Record`、`ReturnType`、`Parameters`、`Awaited`。
**控制流类型窄化**
Null/undefined 检查、`typeof` 守卫、`instanceof`、类型谓词(`x is T`)、断言函数(`asserts x`)、可辨识联合、真值判断、赋值类型窄化、提前返回类型窄化。
**声明**
变量、函数(包含重载)、类(实例 + 静态,继承)、接口(extends、调用/构造签名、索引签名、声明合并)、类型别名、枚举(数字、字符串、混合)、命名空间(声明合并)、导入。
**跨文件解析**
可选。实现 `ModuleResolver` 并设置 `Checker.module_resolver`,以按需解析来自导入模块的类型。
## 一致性
以 TypeScript 编译器本身为基准进行衡量:对于 [microsoft/TypeScript](https://github.com/microsoft/TypeScript) 测试语料库中的每一个表达式,ez-checker 会推断出一种类型,并将其与 `tsc` 为同一表达式生成的 `.types` 基准进行逐字符串比较。
| 指标 | 正确数 | 总数 | 比率 |
| --- | --- | --- | --- |
| 所有表达式类型 | 554,130 | 657,474 | **84.3%** |
| 原始类型(子指标) | 338,560 | 372,262 | **90.9%** |
棘轮机制(`oracle/baseline.lock`)记录了这些下限;如果任何指标出现倒退,`zig build test-oracle` 将会失败,并且 CI 会在每次推送和拉取请求时强制执行此检查。使用 `zig build run-oracle` 扫描语料库;在取得实质性改进后,使用 `zig build save-baseline` 提升下限。
## 已知缺失
完整跟踪列表请参阅[待解决问题](https://github.com/ericsssan/ez-checker/issues/9)。简要说明如下:
- 尚未实现 `ConstructorParameters` 和 `InstanceType`
- 对象字面量上的 `as const`(数组支持;对象不支持)
- 可选链(`?.`)不会为结果类型添加 `| undefined`
- `==`/`!=`(宽松相等)不进行类型窄化
- `throw` 不会对后续代码进行类型窄化
- 不支持类 + 接口声明合并
- 不支持 `declare module` / `declare global` 扩展
- 重载决议会选择第一个匹配的签名,而不是最佳签名
- 全局内置类型(约 30 个手动整理的条目;没有完整的 lib.dom 或 lib.es*)
## 用法
`build.zig.zon`:
```
.dependencies = .{
.ez_checker = .{ .path = "../ez-checker" },
.es_parser = .{ .path = "../es-parser" },
},
```
`build.zig`:
```
const ez_checker_mod = b.dependency("ez_checker", .{
.target = target,
.optimize = .ReleaseFast,
}).module("ez-checker");
your_module.addImport("ez_checker", ez_checker_mod);
```
## API
```
const ez = @import("ez_checker");
const Checker = ez.Checker;
const types = ez.types;
// Init from an already-parsed file.
var checker = try Checker.init(allocator, &ast, &semantic_result);
defer checker.deinit();
// Optional: wire cross-file resolution.
checker.file_path = "/abs/path/to/file.ts";
checker.module_resolver = my_module_cache.resolver();
// Query the type of any expression node.
const ty: types.TypeId = checker.typeOf(node_index);
// Classify the result.
if (types.isAny(&checker.store, ty)) { /* any */ }
if (types.containsAny(&checker.store, ty)) { /* any somewhere inside */ }
if (types.isAssignableTo(&checker.store, src, dst)) { /* assignable */ }
```
### `ModuleResolver`
实现此接口以启用跨文件类型解析:
```
fn resolveImpl(
ctx: *anyopaque,
from_dir: []const u8,
module_spec: []const u8,
export_name: []const u8,
local_store: *types.TypeStore,
gpa: std.mem.Allocator,
) ?types.TypeId {
const cache: *MyCache = @ptrCast(@alignCast(ctx));
return cache.resolve(from_dir, module_spec, export_name, local_store, gpa);
}
checker.module_resolver = .{
.ctx = @ptrCast(my_cache),
.resolve_fn = &resolveImpl,
};
```
## 许可证
MIT
标签:SOC Prime, TypeScript, Zig, 云安全监控, 安全插件, 开发工具, 类型检查器, 编译器组件, 静态分析