eslint icon indicating copy to clipboard operation
eslint copied to clipboard

Change Request: Set minimum supported TypeScript version to v5.3

Open nzakas opened this issue 5 months ago • 13 comments

ESLint version

HEAD

What problem do you want to solve?

We've never formally defined what versions of TypeScript we want to support. This has made making certain decisions more difficult because we're not sure whether type consumers will be using a version of TypeScript that supports the features we want to use.

What do you think is the correct solution?

Set the minimum TypeScript version we formally support to v5.3 and update this along with supported Node.js versions.

Participation

  • [ ] I am willing to submit a pull request for this change.

Additional comments

Split from: https://github.com/eslint/eslint/pull/19843#discussion_r2188973943

nzakas avatar Jul 07 '25 14:07 nzakas

It makes sense to clarify what versions of TypeScript are supported by ESLint. Whether setting the minimum supported TypeScript version to 5.3 is a good choice is open to discussion, and input from the community would be valuable. @eslint/eslint-team @eslint/eslint-community

fasttime avatar Jul 08 '25 08:07 fasttime

+1 to clarifying what versions of TypeScript are supported by ESLint.

As for the version itself, much of the ecosystem aligns with the DefinitelyTyped support window of versions of TypeScript that are less than 2 years old.

Support window for DefinitelyTyped: 5.2 from 2023-08 to 2025-08; 5.3 from 2023-11 to 2025-11; 5.4 from 2024-03 to 2026-03; 5.5 from 2024-06 to 2026-06; 5.6 from 2024-09 to 2026-09; 5.7 from 2024-11 to 2026-11; 5.8 from 2025-02 to 2027-02

You can find DT's full support window history here: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/70305194cccca1d648922c0130eb62740b301fd9/docs/support-window.json#L40

typescript-eslint per https://typescript-eslint.io/users/dependency-versions#typescript currently supports >=4.8.4 <5.9.0. 4.8.4 was the oldest major version supported by DT when the current major version of typescript-eslint, v8, was released.

I think from the perspective of typescript-eslint users, it would be surprising to have the minimum TypeScript version raised from 4.8.4 to 5.3. Obviously (to us) ESLint and typescript-eslint are different projects, but there are users who are still on <5.3 who rely on types in both. I don't have visibility into how many users that is.

If the context for this conversation weren't https://github.com/eslint/eslint/pull/19843#discussion_r2182198631, a TS >=5.3 feature, I would propose aligning with typescript-eslint. But with that context I'm not sure.

JoshuaKGoldberg avatar Jul 08 '25 10:07 JoshuaKGoldberg

@JoshuaKGoldberg thanks for that info, that's very helpful. How do you verify that typescript-eslint is properly functioning with that range of versions?

To summarize what brought us to this point: The @eslint/core package exports types in both ESM and CommonJS formats. Because the eslint package is CommonJS, it imports the CommonJS types. Most consumers are ESM, which means they end up using the ESM types from @eslint/core. This matters when folks want to extends interfaces from @eslint/core expecting them to apply inside of ESLint (i.e., RulesConfig). This is the infamous npm "dual module hazard."

One way to fix this is to have the eslint package import the ESM types from @eslint/core. As far as I can tell, there are two ways to do this:

  1. Use the TypeScript import-resolution option when importing the types (this is available as of v5.3)
  2. Convert the eslint package to ESM -- this would be a breaking change

Of the two, option 1 is definitely the easier. If there are other options, please feel free to share.

nzakas avatar Jul 08 '25 15:07 nzakas

Now that require(esm) is a becoming commonplace, I wonder if it would make sense to deduplicate types altogether? Continuing the "dual module" parallel, this would effectively be publishing only ESM and adding a thin CommonJS shim on top for folks still in CJS-land. Kind of like what @lumirlumir has in https://github.com/eslint/markdown/pull/453#issuecomment-3052272731.

The types all behave the same in CJS vs. ESM, right? Is the only divergence the way they're imported?

JoshuaKGoldberg avatar Jul 09 '25 21:07 JoshuaKGoldberg

Yes, the only divergence is the way they're imported.

require(esm) requires Node.js v20.x, and we're still supporting Node.js v18.x. I'm also not sure if this matters because the type importing is done via TypeScript not through Node.js. You'd know better than I how that works.

nzakas avatar Jul 10 '25 16:07 nzakas

Ok then great. I think I understand the problem but am still catching up on the reasons behind the current structure. There's no actual file difference between core's dist/cjs/types.d.cts and dist/esm/types.d.ts. Is there a reason that they couldn't be deduplicated? I.e. only have a single dist/types.d.ts used for both CJS and ESM consumers?

"exports": {
  "types": "./dist/types.d.ts"
},

How do you verify that typescript-eslint is properly functioning with that range of versions?

We, ah, don't. It's been on the 'todo' list for a while: https://github.com/typescript-eslint/typescript-eslint/issues/1752.

JoshuaKGoldberg avatar Jul 15 '25 17:07 JoshuaKGoldberg

There's no actual file difference between core's dist/cjs/types.d.cts and dist/esm/types.d.ts. Is there a reason that they couldn't be deduplicated? I.e. only have a single dist/types.d.ts used for both CJS and ESM consumers?

"exports": { "types": "./dist/types.d.ts" },

@eslint/core is an ESM package, meaning that dist/types.d.ts would be treated as ESM by TypeScript with "moduleResolution": "nodenext". But ESM types cannot be imported in CommonJS code without using an import attribute. This is also the reason why core CommonJS types were added in eslint/rewrite#95.

fasttime avatar Jul 17 '25 17:07 fasttime

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

github-actions[bot] avatar Aug 16 '25 22:08 github-actions[bot]

Not stale

lishaduck avatar Aug 18 '25 01:08 lishaduck

Oh, yes, I need to really deeply look into the options for joining the types into one. It's tricky given what fasttime noted. I'm not sure I'll be able to by the end of the month, so if anybody else wants to please go ahead.

JoshuaKGoldberg avatar Aug 18 '25 16:08 JoshuaKGoldberg

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

github-actions[bot] avatar Sep 18 '25 22:09 github-actions[bot]

Not stale. This is something we could think about after the v10 release.

fasttime avatar Sep 19 '25 08:09 fasttime

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

github-actions[bot] avatar Oct 19 '25 22:10 github-actions[bot]