Recap: Typed Linting? 回顾:打字的 Linting?
Linting with type information, also called “typed linting” or “type-aware linting”, is the act of writing lint rules that use type information to understand your code.
Typed linting as provided by typescript-eslint is the most powerful JavaScript/TypeScript linting in common use today.
Lint rules that use type information are significantly more capable than traditional, AST-only rules.
使用类型信息进行 linting,也称为“类型化 linting”或“类型感知 linting”,是编写使用类型信息来理解代码的 lint 规则的行为。typescript-eslint 提供的键入 linting 是当今常用的最强大的 JavaScript/TypeScript linting。使用类型信息的 Lint 规则比传统的仅限 AST 的规则功能更强大。
👉 For a deeper explanation of typed linting, see the deploy preview of typescript-eslint > Typed Linting: The Most Powerful TypeScript Linting Ever, a work-in-progress blog post.
👉 有关类型化 linting 的更深入解释,请参阅 typescript-eslint > Typed Linting: The Most Powerful TypeScript Linting Ever, a short-in progress 博客文章的部署预览。
Many popular lint rules have ended up either dependent on typed linting or having to deal with known bugs or feature gaps without typed linting 1 2.
ESLint’s core rules don’t understand type information, leading to some typescript-eslint “extension” rules adding in type information 3.
许多流行的 lint 规则最终要么依赖于类型化 linting,要么不得不在没有类型化 linting 的情况下处理已知错误或功能差距 12。ESLint 的核心规则不理解类型信息,导致一些 typescript-eslint 的 “extension” 规则添加了类型信息 3.
So, typed linting is really, really important for a linter.
所以,typed linting 对于 linter 来说真的非常重要。
And how do you get type information?
Well…
你如何获取类型信息?井。。。
TypeScript For Type Information
TypeScript 用于类型信息
TypeScript is the tool for providing full TypeScript type information on JavaScript or TypeScript code.
It’s by far the most popular flavor of JavaScript during this era of web development.
TypeScript 是提供有关 JavaScript 或 TypeScript 代码的完整 TypeScript 类型信息的工具。到目前为止,它是这个 Web 开发时代最流行的 JavaScript 风格。
In fact, TypeScript is the only tool that can reasonably retrieve type information today.
Every public effort to recreate it is either abandoned4 or stalled5.
Flow is explicitly not targeting competing with TypeScript for public mindshare6.
The closest publicly known effort right now is Ezno, which is very early stage.
事实上,TypeScript 是当今唯一可以合理检索类型信息的工具。每一次重建它的公众努力要么被放弃4 ,要么停滞不前5。Flow 明确地不打算与 TypeScript 竞争公众的心智份额6.目前最接近公众知晓的努力是 Ezno,它处于非常早期的阶段。
If you want a full type checker for your JavaScript/TypeScript project (which, again, you do), then TypeScript is your only reasonable choice today.
如果你想要一个完整的 JavaScript/TypeScript 项目类型检查器(同样,你也这样做),那么 TypeScript 是你今天唯一合理的选择。
Alternatives and Difficulties
替代方案和困难
TypeScript is a large dependency.
Type checking is a notoriously expensive process.
TypeScript executes at JavaScript speeds (“JIT”, or Just In Time compiling), and so takes up exponentially more memory and execution time than tooling written in native speed languages such as Go or Rust.
TypeScript 是一个很大的依赖项。众所周知,类型检查是一个非常昂贵的过程。TypeScript 以 JavaScript 速度(“JIT”或即时编译)执行,因此比用 Go 或 Rust 等原生速度语言编写的工具占用的内存和执行时间呈指数级增长。
It would be fantastic for linter users if we could find away around having to run the full JIT speed type checker as part of our typed linting.
Such a feat has not been successfully implemented yet.
如果我们能发现必须运行完整的 JIT 速度类型检查器作为我们键入的 linting 的一部分,那对 linter 用户来说将是非常棒的。这样的壮举尚未成功实施。
AST-Only Types 仅限 AST 的类型
One way to avoid a TypeScript dependency could be to support only limited type retrievals: effectively only looking at what’s visible in the AST.
I’d wager you could get somewhat far with basic AST checks in a file for many functions, and even further with a basic TypeScript parser that builds up a scope manager for each file and effectively looks up where identifiers are declared.
避免 TypeScript 依赖项的一种方法是仅支持有限的类型检索:有效地只查看 AST 中可见的内容。我敢打赌,对于许多函数,您可以在文件中进行基本的 AST 检查,甚至可以使用基本的 TypeScript 解析器来进一步发展,该解析器为每个文件构建了一个范围管理器,并有效地查找声明标识符的位置。
Sadly, an AST-only type lookup system falls apart fairly quickly in the presence of any complex TypeScript types (e.g. conditional or mapped types).
Most larger TypeScript projects end up using complex types somewhere in the stack.
Any modern ORM (e.g. Prisma, Supabase) or schema validation library (e.g. Arktype, Zod) employs conditional types and other shenanigans.
Not being able to understand those types blocks rules from understanding any code referencing those types.
可悲的是,在存在任何复杂的 TypeScript 类型(例如条件或映射类型)的情况下,仅限 AST 的类型查找系统很快就会崩溃。大多数较大的 TypeScript 项目最终在堆栈中的某个位置使用复杂类型。任何现代 ORM(例如 Prisma、Supabase)或模式验证库(例如 Arktype、Zod)都使用条件类型和其他恶作剧。无法理解这些类型会阻止规则理解引用这些类型的任何代码。
Inconsistent levels of type-awareness are at best confusing for users.
They’re practically a blocker to real adoption of a linter.
不一致的类型识别级别充其量会让用户感到困惑。它们实际上是真正采用 linter 的障碍。
A full type system such as TypeScript’s is the only way path to fully working lint rules that perform any go-to-definition or type-dependent logic.
完整的类型系统(如 TypeScript 的类型系统)是实现完全有效的 lint 规则的唯一途径,这些规则可执行任何转到定义或类型依赖的逻辑。
Native Speed Reimplementation
原生速度重新实现
I previously touched on similar points in Rust-Based JavaScript Linters: Fast, But No Typed Linting Right Now > Option: Reimplementing TypeScript at Native Speed.
我之前在基于 Rust 的 JavaScript Linters: Fast, But no typed linting now > 选项:以本机速度重新实现 TypeScript 中提到了类似的观点。
If type checking is so important, and a native speed type checker would be so beneficial, why hasn’t one been written yet?
Why hasn’t anybody reimplemented TypeScript in, say, Go or Rust?
如果类型检查如此重要,并且原生速度类型检查器如此有益,为什么还没有编写一个呢?为什么没有人在 Go 或 Rust 中重新实现 TypeScript?
TypeScript is a huge project under active development from a funded team of incredibly dedicated, experienced Microsoft employees — as well as an active community of power users and contributors.
The TypeScript team receives the equivalent of millions of dollars a year in funding from employee compensation alone.
A new version of TypeScript that adds type checking bugfixes and features releases every three months.
TypeScript 是一个正在积极开发的巨大项目,由一支由非常敬业、经验丰富的 Microsoft 员工组成的资助团队以及一个由高级用户和贡献者组成的活跃社区积极开发。仅从员工薪酬中,TypeScript 团队每年就获得相当于数百万美元的资金。TypeScript 的新版本,添加了类型检查、错误修复和功能,每三个月发布一次。
Can you imagine the Herculean difficulty for any team trying to keep up with TypeScript?
你能想象任何试图跟上 TypeScript 的团队所面临的巨大困难吗?
I hope for a day when there is a tool that can fully compete with TypeScript.
Competition is good for an ecosystem.
But it’s going to be years until a tool like that can develop.
我希望有一天,有一个工具可以与 TypeScript 完全竞争。竞争对生态系统有好处。但这样的工具需要几年时间才能开发出来。
Subset Reimplementation 子集重新实现
TypeScript consists of several big areas of functionality, of which type checking is only one.
The areas of type checking used by typed linting theoretically revolves around two areas of APIs:
TypeScript 由几个主要的功能区域组成,其中类型检查只是其中的一个。从理论上讲,类型化 linting 使用的类型检查领域围绕 API 的两个领域:
- Type retrieval (“what type is this node?”)
类型检索(“What type is this node?”) - Type relations (“is this type assignable to that type?”)
类型关系(“此类型是否可以分配给该类型?
Most typed lint rule in practice today only use the retrieval part of the type checker.
Reimplementing only that portion of TypeScript could significantly reduce the development cost of the reimplementation.
目前,大多数类型化 lint 规则实际上只使用类型检查器的检索部分。仅重新实现 TypeScript 的这一部分可以显著降低重新实现的开发成本。
Unfortunately, the relations portion of TypeScript was recently confirmed to be ready for use by linters7.
typescript-eslint is going to start building in rule logic that builds on checker.isTypeAssignableTo
.
不幸的是,TypeScript 的 relations 部分最近被确认可供 linters7 使用。typescript-eslint 将开始构建基于 checker.isTypeAssignableTo
的规则逻辑。
Any subset reimplementation of TypeScript would need to include equivalents both for the existing type retrieval and type relations APIs.
Those APIs include most of the tricky assignability logic that makes TypeScript so hard to reimplement in the first place.
TypeScript 的任何子集重新实现都需要包含现有类型检索和类型关系 API 的等效项。这些 API 包含大多数棘手的可分配性逻辑,这些逻辑首先使 TypeScript 难以重新实现。
A subset reimplementation of TypeScript for typed linting is tempting, but not as narrowly scoped of a task as it might seem.
The scope of TypeScript that must be implemented is actually a substantial portion of its APIs’ logic.
TypeScript 的子集重新实现以进行类型化 linting 很诱人,但并不像看起来那样狭隘地限制任务。必须实现的 TypeScript 范围实际上是其 API 逻辑的很大一部分。
Automatically Porting TypeScript to Native Speed
自动将 TypeScript 移植到 Native Speed
I previously touched on similar points in Rust-Based JavaScript Linters: Fast, But No Typed Linting Right Now > Option: Boosting TypeScript’s APIs to Native Speed.
我之前在基于 Rust 的 JavaScript Linters: Fast, But No Typed Linting Now > 选项:将 TypeScript 的 API 提升到本机速度中提到了类似的观点。
Instead of reimplementing TypeScript from scratch, what if we could automatically port its source code to a faster language?
与其从头开始重新实现 TypeScript,不如自动将其源代码移植到更快的语言中呢?
Well, TypeScript has tens of thousands of lines of source code built for single-threaded JavaScript with dynamic objects.
It’s really not architected to work in another paradigm.
TypeScript 有数万行源代码,专为具有动态对象的单线程 JavaScript 构建。它真的不是为了在另一种范式中工作而设计的。
I think this approach is very promising for getting a TypeScript equivalent that stays up-to-date, but the difficulty is very high.
I’ve yet to see anybody make any significant progress on this idea beyond proof-of-concepts.
我认为这种方法对于获得保持最新的 TypeScript 等效项非常有前途,但难度非常高。我还没有看到有人在概念验证之外的这个想法上取得任何重大进展。
Closing Thoughts 结束语
TypeScript itself is the only stable, production-ready tool available right now for typed linting on TypeScript code.
It’s got a monopoly on usable type checking APIs.
Being able to use a faster equivalent would be fantastic for users of typed linting, but none have become production ready yet.
TypeScript 本身是目前唯一可用于 TypeScript 代码类型化 linting 的稳定、生产就绪工具。它垄断了可用的类型检查 API。能够使用更快的等效方法对于类型化 linting 的用户来说非常棒,但还没有一个可用于生产。
There are a lot of obstacles to reimplementing TypeScript or an equivalent to it. And every year, TypeScript gets more complex and fully-featured.
I’m hopeful that a true competitor to TypeScript will eventually rise up and introduce more healthy competition into the ecosystem. Or failing that, either a subset of TypeScript that can speed up API consumers such as typed linting, or an automated TypeScript-to-native-speed port.
But, it’s going to be a while until anything remotely capable of competing with TypeScript stabilizes. We’re stuck with TypeScript for typed linting for now.
Footnotes
-
facebook/react#25065 Bug: Eslint hooks returned by factory functions not linted ↩
-
vitest-dev/eslint-plugin-vitest#251 valid-type: use type checking to determine test name type? ↩
-
typescript-eslint.io > Rules > Extension & Type Information. ↩
-
marcj/TypeRunner Is there still a chance of kickstarting the project? ↩