Skip to content

type aware linting blog post #424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vitepress/config/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const enConfig = defineLocaleConfig("root", {
{
text: "Resources",
items: [
{ text: "Blog", link: "/blog/2025-06-10-oxlint-stable" },
{ text: "Blog", link: "/blog/2025-07-24-oxlint-type-aware" },
{ text: "Team", link: "/team" },
{ text: "Branding", link: "/branding" },
{ text: "Website GitHub", link: "https://github.com/oxc-project/oxc-project.github.io" },
Expand Down
4 changes: 4 additions & 0 deletions .vitepress/sidebar.blog.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
[
{
"text": "Oxlint Type-Aware Rules",
"link": "/blog/2025-07-24-oxlint-type-aware"
},
{
"text": "Oxlint v1.0 Stable",
"link": "/blog/2025-06-10-oxlint-stable"
Expand Down
4 changes: 2 additions & 2 deletions .vitepress/theme/components/Banner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const hide = () => {
document.documentElement.classList.add("banner-dismissed");
};

const slug = "/blog/2025-06-10-oxlint-stable";
const slug = "/blog/2025-07-24-oxlint-type-aware";

const bannerDismissed = useLocalStorage<boolean>(`oxc-banner-dismissed-${slug}`, false);

Expand Down Expand Up @@ -45,7 +45,7 @@ const dismiss = () => {

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

<button type="button" @click="dismiss">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
Expand Down
12 changes: 12 additions & 0 deletions .vitepress/theme/constants/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ export const CORE_MEMBERS: TeamMember[] = [
{ icon: "x", link: "https://x.com/yagiznizipli" },
],
},
{
id: "auvred",
type: "consultant",
name: "auvred",
title: "tsgolint",
avatar: "https://www.github.com/auvred.png",
org: "typescript-eslint",
orgLink: "https://github.com/typescript-eslint",
links: [
{ icon: "github", link: "https://github.com/auvred" },
],
},
];

export const CORE_TEAM_MEMBERS = CORE_MEMBERS.filter(({ type }) => type === "core") as CoreTeamMember[];
Expand Down
163 changes: 163 additions & 0 deletions src/blog/2025-07-24-oxlint-type-aware.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
---
title: Oxlint Type-Aware Preview
outline: deep
authors:
- boshen
- camchenry
- auvred
---

<AppBlogPostHeader />

<br>

We're thrilled to announce type-aware rules support in Oxlint!

This preview release aims to engage with the community for collaboration and
discussion by documenting our decision process and technical details.

## Quick Start

If oxlint isn't already installed, please visit our [usage guide](https://oxc.rs/docs/guide/usage/linter.html).

To get started, run:

```bash
pnpm add -D oxlint-tsgolint
oxlint --tsconfig tsconfig.json
```

You'll then see two of our most requested type-aware rules in action:

- `no-floating-promises`
- `no-misused-promises`

The next version will enable all type-aware rules.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in: The next major or the next minor version?


## Performance

Our testing shows that large repositories, which previously took several minutes to run with `typescript-eslint`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have more precise metrics?

now complete in less than 10 seconds.

We achieved this by leveraging [`typescript-go`](https://github.com/microsoft/typescript-go),
the [10x faster TypeScript](https://devblogs.microsoft.com/typescript/typescript-native-port) written in Go.

## Type-Aware linting

Please refer to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might still be worth to add a bit of an overview to what other type-aware linters are doing (e.g. biome)?

[Rust-Based JavaScript Linters: Fast, But No Typed Linting Right Now](https://www.joshuakgoldberg.com/blog/rust-based-javascript-linters-fast-but-no-typed-linting-right-now)
to understand the current status of type-aware linting in the ecosystem.

## Technical Details

The core of this new functionality is [oxc-project/tsgolint](https://github.com/oxc-project/tsgolint).

The tsgolint project was initially prototyped as [typescript-eslint/tsgolint](https://github.com/typescript-eslint/tsgolint).
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth pointing out (in a different chapter) what is the USP of using tsgolint with oxlint (instead of, e.g., waiting for typescript-eslint to be "go-powered")?


@boshen then reached out to @auvred for a forked, scoped-down version adapted for oxlint.
This version would only contain type-aware rules without the sophisticated configuration resolution a full linter would require.

@auvred generously offered to continue its development under the Oxc organization.

### Architecture

`oxlint` (written in Rust) and `tsgolint` (written in Go) are compiled into their own binaries.

`oxlint` serves as the "frontend" for `tsgolint`, handling the CLI, path traversal, ignore logic, and diagnostic printing.

`tsgolint` acts as the backend for `oxlint`, accepting paths and configuration as input and outputting structured diagnostics.

This creates a simple pipeline:

```
Oxlint CLI (returns paths + rules + configuration)
-> tsgolint (returns diagnostics)
-> Oxlint CLI
```

### `tsgolint`

`tsgolint` does not communicate with typescript-go via public APIs.

Instead, it compiles `typescript-go` by [shimming its internal APIs to make them public](https://github.com/oxc-project/tsgolint/tree/main/shim).

All type-aware rules are written directly against these shimmed APIs.

While this isn't the recommended approach for accessing internals, it works!

## Decision Process

### Write our own type checker

Previous abandoned attempts to implement a type checker included:

- My own attempt at [writing type inference](https://gist.github.com/Boshen/d189de0fe0720a30c5182cb666e3e9a5)
- [Integrate](https://github.com/oxc-project/oxc/pull/413) [ezno type checker](https://github.com/kaleidawave/ezno) by @kaleidawave
- [stc](https://github.com/dudykr/stc) by @kdy1
- (There are also many attempts in the community that did not go far).

Additionally, there's the work-in-progress:

- [Biome 2.0](https://biomejs.dev/blog/biome-v2/) with its own type inference implementation.

We determined that writing our own type inferencer or type checker was not feasible due to
the challenge of keeping up with a fast-moving target like TypeScript.

### Communication with TypeScript

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:

- [typescript-eslint](https://typescript-eslint.io/getting-started/typed-linting)
- [tsslint](https://github.com/johnsoncodehk/tsslint)
- [tsl](https://github.com/ArnaudBarre/tsl)

We also explored [inter-process communication with Oxlint](https://github.com/oxc-project/oxc/discussions/2855) but abandoned the idea.

With `typescript-go`, the TypeScript team is [leaning towards](https://github.com/microsoft/typescript-go/discussions/455)
encoding the TypeScript AST and decoding it on the JavaScript side through inter-process communication.

While these approaches work, they still incur:

- Performance issues of varying degrees that don't suit Oxlint's performance characteristics.
- The cost of maintaining an AST mapping from TypeScript's AST.

## Considerations

While `tsgolint` solves the performance issue, there are other technical challenges that need to be addressed.

### Requirement for a Different TypeScript Version

We plan to release snapshots of `typescript-go` versions and align their version numbers with TypeScript.
You will then be able to install `oxlint-typescript` with the correct TypeScript version.

The downside of this approach is that you may need to upgrade TypeScript if `oxlint-tsgolint` requires changes.

### Maintenance cost of `tsgolint`

Shimming TypeScript's internal APIs carries some risk. However, the TypeScript AST and its visitor are actually quite stable.
We accept this risk and will fix breaking changes when upgrading `typescript-go`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth highlighting the reduced risk for users through this?


Our `typescript-go` version is synced three times a week.

## Acknowledgements

We'd like to extend our gratitude to:

- The TypeScript team for creating `typescript-go`.
- [@auvred](https://github.com/auvred) for creaging `tsgolint`.
- [@camchenry](https://github.com/camchenry) for the `oxlint` + `tsgolint` integration.
- The `typescript-eslint` team for their heartwarming support.

## Join the Community

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.
Connect with us:

- **Discord**: Join our [community server](https://discord.gg/9uXCAwqQZW) for real-time discussions
- **GitHub**: Share feedback on [GitHub Discussions](https://github.com/oxc-project/oxc/discussions)
- **Issues**: Report bugs or request features on our [issue tracker](https://github.com/oxc-project/oxc/issues)

## Give It a Try

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).