Skip to content

Commit b30e6c1

Browse files
committed
type aware linting blog post
1 parent 7ede383 commit b30e6c1

File tree

5 files changed

+177
-3
lines changed

5 files changed

+177
-3
lines changed

.vitepress/config/en.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const enConfig = defineLocaleConfig("root", {
2323
{
2424
text: "Resources",
2525
items: [
26-
{ text: "Blog", link: "/blog/2025-06-10-oxlint-stable" },
26+
{ text: "Blog", link: "/blog/2025-07-24-oxlint-type-aware" },
2727
{ text: "Team", link: "/team" },
2828
{ text: "Branding", link: "/branding" },
2929
{ text: "Website GitHub", link: "https://github.com/oxc-project/oxc-project.github.io" },

.vitepress/sidebar.blog.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
[
2+
{
3+
"text": "Oxlint Type-Aware Rules",
4+
"link": "/blog/2025-07-24-oxlint-type-aware"
5+
},
26
{
37
"text": "Oxlint v1.0 Stable",
48
"link": "/blog/2025-06-10-oxlint-stable"

.vitepress/theme/components/Banner.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const hide = () => {
1616
document.documentElement.classList.add("banner-dismissed");
1717
};
1818
19-
const slug = "/blog/2025-06-10-oxlint-stable";
19+
const slug = "/blog/2025-07-24-oxlint-type-aware";
2020
2121
const bannerDismissed = useLocalStorage<boolean>(`oxc-banner-dismissed-${slug}`, false);
2222
@@ -45,7 +45,7 @@ const dismiss = () => {
4545

4646
<template>
4747
<div ref="el" class="banner banner-dismissed">
48-
<div class="text"><a :href="slug">Announcing Oxlint v1.0 Stable</a> 🎉</div>
48+
<div class="text"><a :href="slug">Announcing Oxlint Type-Aware Preview</a> 🎉</div>
4949

5050
<button type="button" @click="dismiss">
5151
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">

.vitepress/theme/constants/team.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ export const CORE_MEMBERS: TeamMember[] = [
152152
{ icon: "x", link: "https://x.com/yagiznizipli" },
153153
],
154154
},
155+
{
156+
id: "auvred",
157+
type: "consultant",
158+
name: "auvred",
159+
title: "tsgolint",
160+
avatar: "https://www.github.com/auvred.png",
161+
org: "typescript-eslint",
162+
orgLink: "https://github.com/typescript-eslint",
163+
links: [
164+
{ icon: "github", link: "https://github.com/auvred" },
165+
],
166+
},
155167
];
156168

157169
export const CORE_TEAM_MEMBERS = CORE_MEMBERS.filter(({ type }) => type === "core") as CoreTeamMember[];
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
---
2+
title: Oxlint Type-Aware Preview
3+
outline: deep
4+
authors:
5+
- boshen
6+
- camchenry
7+
- auvred
8+
---
9+
10+
<AppBlogPostHeader />
11+
12+
<br>
13+
14+
We're thrilled to announce type-aware rules support in Oxlint!
15+
16+
This preview release aims to engage with the community for collaboration and
17+
discussion by documenting our decision process and technical details.
18+
19+
## Quick Start
20+
21+
If oxlint isn't already installed, please visit our [usage guide](https://oxc.rs/docs/guide/usage/linter.html).
22+
23+
To get started, run:
24+
25+
```bash
26+
pnpm add -D oxlint-tsgolint
27+
oxlint --tsconfig tsconfig.json
28+
```
29+
30+
You'll then see two of our most requested type-aware rules in action:
31+
32+
- no-floating-promises
33+
- no-misused-promises
34+
35+
The next version will enable all type-aware rules.
36+
37+
## Performance
38+
39+
Our testing shows that large repositories, which previously took several minutes to run with `typescript-eslint`,
40+
now complete in less than 10 seconds.
41+
42+
We achieved this by leveraging [`typescript-go`](https://github.com/microsoft/typescript-go),
43+
the [10x faster TypeScript](https://devblogs.microsoft.com/typescript/typescript-native-port) written in Go.
44+
45+
## Technical Details
46+
47+
The core of this new functionality is [oxc-project/tsgolint](https://github.com/oxc-project/tsgolint).
48+
49+
The tsgolint project was initially prototyped as [typescript-eslint/tsgolint](https://github.com/typescript-eslint/tsgolint).
50+
However, the `typescript-eslint` team decided not to allocate development resources to this prototype, as they plan to continue their work on `typescript-eslint` for typed linting with ESLint.
51+
52+
@boshen then reached out to @auvred for a forked, scoped-down version adapted for oxlint.
53+
This version would only contain type-aware rules without the sophisticated configuration resolution a full linter would require.
54+
55+
@auvred generously offered to continue its development under the Oxc organization.
56+
57+
### Architecture
58+
59+
oxlint (written in Rust) and tsgolint (written in Go) are compiled into their own binaries.
60+
61+
Oxlint serves as the "frontend" for tsgolint, handling the CLI, path traversal, ignore logic, and diagnostic printing.
62+
63+
tsgolint acts as the backend for Oxlint, accepting paths and configuration as input and outputting structured diagnostics.
64+
65+
This creates a simple pipeline:
66+
67+
```
68+
Oxlint CLI (returns paths + rules + configuration)
69+
-> tsgolint (returns diagnostics)
70+
-> Oxlint CLI
71+
```
72+
73+
### `tsgolint`
74+
75+
`tsgolint` does not communicate with typescript-go via public APIs.
76+
77+
Instead, it compiles `typescript-go` by [shimming its internal APIs to make them public](https://github.com/oxc-project/tsgolint/tree/main/shim).
78+
79+
All type-aware rules are written directly against these shimmed APIs.
80+
81+
While this isn't the recommended approach, it works!
82+
83+
## Decision Process
84+
85+
### Write our own type checker
86+
87+
Previous abandoned attempts to implement a type checker included:
88+
89+
- My own attempt at [writing type inference](https://gist.github.com/Boshen/d189de0fe0720a30c5182cb666e3e9a5)
90+
- [Integrate](https://github.com/oxc-project/oxc/pull/413) [ezno type checker](https://github.com/kaleidawave/ezno) by @kaleidawave
91+
- [stc](https://github.com/dudykr/stc) by @kdy1
92+
- (There are also many attempts in the community that did not go far).
93+
94+
Additionally, there's the work-in-progress:
95+
96+
- [Biome 2.0](https://biomejs.dev/blog/biome-v2/) with its own type inference implementation.
97+
98+
We determined that writing our own type inferencer or type checker was not feasible due to budget and time constraints,
99+
implementation details, and the challenge of keeping up with a fast-moving target like TypeScript.
100+
101+
### Communication with TypeScript
102+
103+
Prior to `typescript-go`, projects added plugin interfaces to TypeScript's public API by either mapping its AST to `estree` or directly traversing the TypeScript AST. Examples include:
104+
105+
- [typescript-eslint](https://typescript-eslint.io/getting-started/typed-linting)
106+
- [tsslint](https://github.com/johnsoncodehk/tsslint)
107+
- [tsl](https://github.com/ArnaudBarre/tsl)
108+
109+
We also explored [inter-process communication with Oxlint](https://github.com/oxc-project/oxc/discussions/2855) but abandoned the idea.
110+
111+
With `typescript-go`, the TypeScript team is [leaning towards](https://github.com/microsoft/typescript-go/discussions/455)
112+
encoding the TypeScript AST and decoding it on the JavaScript side through inter-process communication.
113+
114+
While these approaches work, they still incur:
115+
116+
- Performance issues of varying degrees that don't suit Oxlint's performance characteristics.
117+
- The cost of maintaining an AST mapping from TypeScript's AST.
118+
119+
## Considerations
120+
121+
While `tsgolint` solves the performance issue, there are other technical challenges that need to be addressed.
122+
123+
### Requirement for a Different TypeScript Version
124+
125+
We plan to release snapshots of `typescript-go` versions and align their version numbers with TypeScript.
126+
You will then be able to install `oxlint-typescript` with the correct TypeScript version.
127+
128+
The downside of this approach is that you may need to upgrade TypeScript if `oxlint-tsgolint` requires changes.
129+
130+
### Maintainance cost of `tsgolint`
131+
132+
Shimming TypeScript's internal APIs carries some risk. However, the TypeScript AST and its visitor are actually quite stable.
133+
134+
We accept this risk and will fix breaking changes when upgrading `typescript-go`.
135+
136+
Our `typescript-go` version is synced three times a week.
137+
138+
## Acknowledgements
139+
140+
We'd like to extend our gratitude to:
141+
142+
- The TypeScript team for creating `typescript-go`.
143+
- [@auvred](https://github.com/auvred) for creaging `tsgolint`.
144+
- [@camchenry](https://github.com/camchenry) for the `oxlint` + `tsgolint` integration.
145+
- The `typescript-eslint` team for their heartwarming support.
146+
147+
## Join the Community
148+
149+
We'd love to hear your feedback on Oxlint and type-aware linting and are excited to see how it helps improve your development workflow.
150+
Connect with us:
151+
152+
- **Discord**: Join our [community server](https://discord.gg/9uXCAwqQZW) for real-time discussions
153+
- **GitHub**: Share feedback on [GitHub Discussions](https://github.com/oxc-project/oxc/discussions)
154+
- **Issues**: Report bugs or request features on our [issue tracker](https://github.com/oxc-project/oxc/issues)
155+
156+
## Give It a Try
157+
158+
To get started, follow the [installation guide](https://oxc.rs/docs/guide/usage/linter), or learn more about the [Oxc project](https://oxc.rs/docs/guide/introduction).

0 commit comments

Comments
 (0)