Change Request: Set minimum supported TypeScript version to v5.3
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
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
+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.
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 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:
- Use the TypeScript
import-resolutionoption when importing the types (this is available as of v5.3) - Convert the
eslintpackage 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.
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?
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.
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.
There's no actual file difference between core's
dist/cjs/types.d.ctsanddist/esm/types.d.ts. Is there a reason that they couldn't be deduplicated? I.e. only have a singledist/types.d.tsused 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.
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.
Not stale
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.
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.
Not stale. This is something we could think about after the v10 release.
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.