Skip to content

Commit a8e71d5

Browse files
committed
feat: bump minimum supported TS version to 4.2.4 (#5915)
BREAKING CHANGE: Bumps the minimum supported range and removes handling for old versions
1 parent 7e3fe9a commit a8e71d5

File tree

10 files changed

+36
-165
lines changed

10 files changed

+36
-165
lines changed

README.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,37 @@ The latest version under the `canary` tag **(latest commit to `main`)** is:
5151

5252
### Supported TypeScript Version
5353

54-
**The version range of TypeScript currently supported by this parser is `>=3.3.1 <5.0.0`.**
54+
**The version range of TypeScript currently supported by this parser is `>=4.2.0 <5.0.0`.**
5555

56-
These versions are what we test against.
56+
Note that we mirror [DefinitelyTyped's version support window](https://github.com/DefinitelyTyped/DefinitelyTyped/#support-window) - meaning we only support versions of TypeScript less than 2 years old.
5757

58-
We will always endeavor to support the latest stable version of TypeScript.
59-
Sometimes, but not always, changes in TypeScript will not require breaking changes in this project, and so we are able to support more than one version of TypeScript.
60-
In some cases, we may even be able to support additional pre-releases (i.e. betas and release candidates) of TypeScript, but only if doing so does not require us to compromise on support for the latest stable version.
58+
You may find that our tooling works on older TypeScript versions however we provide no guarantees and **_we will not accept issues against unsupported versions_**.
59+
60+
#### Supporting New TypeScript Releases
61+
62+
With each new TypeScript release we file an issue to track the changes in the new version. The issue should always be pinned, and you can also [find the issues by searching for issues tagged with "New TypeScript Version"](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+label%3A%22New+TypeScript+Version%22+sort%3Acreated-desc). If the issue is open, we do not have official support yet - please be patient.
63+
64+
In terms of what versions we support:
65+
66+
- We do not support the `beta` releases.
67+
- We _generally_ do not officially support the `rc` releases.
68+
- We endeavor to support the latest stable TypeScript versions as soon as possible after the release.
69+
70+
Generally we will begin working on supporting the next release when the `rc` version is released.
71+
72+
#### Version Warning Logs
6173

6274
Note that our packages have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript.
6375

64-
If you use a non-supported version of TypeScript, the parser will log a warning to the console.
76+
However if you use a non-supported version of TypeScript, the parser will log a warning to the console.
6577
If you want to disable this warning, you can configure this in your `parserOptions`. See: [`@typescript-eslint/parser`](./packages/parser/) and [`@typescript-eslint/typescript-estree`](./packages/typescript-estree/).
6678

6779
**Please ensure that you are using a supported version before submitting any issues/bug reports.**
6880

6981
### Supported ESLint Version
7082

83+
We endeavour to support the latest stable ESLint versions as soon as possible after the release.
84+
7185
See the value of `eslint` declared in `@typescript-eslint/eslint-plugin`'s [package.json](./packages/eslint-plugin/package.json).
7286

7387
### Supported Node Version

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
"tmp": "^0.2.1",
106106
"ts-node": "^10.7.0",
107107
"tslint": "^6.1.3",
108-
"typescript": ">=3.3.1 <5.0.0"
108+
"typescript": ">=4.2.4 <5.0.0"
109109
},
110110
"resolutions": {
111111
"typescript": "~4.9.3",
Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
11
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
2-
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
3-
import * as semver from 'semver';
4-
import * as ts from 'typescript';
52

63
import * as util from '../util';
74

8-
const is3dot9 = semver.satisfies(
9-
ts.version,
10-
`>= 3.9.0 || >= 3.9.1-rc || >= 3.9.0-beta`,
11-
{
12-
includePrerelease: true,
13-
},
14-
);
15-
165
export default util.createRule({
176
name: 'no-non-null-asserted-optional-chain',
187
meta: {
@@ -32,16 +21,7 @@ export default util.createRule({
3221
},
3322
defaultOptions: [],
3423
create(context) {
35-
// TS3.9 made a breaking change to how non-null works with optional chains.
36-
// Pre-3.9, `x?.y!.z` means `(x?.y).z` - i.e. it essentially scrubbed the optionality from the chain
37-
// Post-3.9, `x?.y!.z` means `x?.y!.z` - i.e. it just asserts that the property `y` is non-null, not the result of `x?.y`.
38-
// This means that for > 3.9, x?.y!.z is valid!
39-
//
40-
// NOTE: these cases are still invalid for 3.9:
41-
// - x?.y.z!
42-
// - (x?.y)!.z
43-
44-
const baseSelectors = {
24+
return {
4525
// non-nulling a wrapped chain will scrub all nulls introduced by the chain
4626
// (x?.y)!
4727
// (x?.())!
@@ -89,62 +69,5 @@ export default util.createRule({
8969
});
9070
},
9171
};
92-
93-
if (is3dot9) {
94-
return baseSelectors;
95-
}
96-
97-
return {
98-
...baseSelectors,
99-
[[
100-
// > :not(ChainExpression) because that case is handled by a previous selector
101-
'MemberExpression > TSNonNullExpression.object > :not(ChainExpression)',
102-
'CallExpression > TSNonNullExpression.callee > :not(ChainExpression)',
103-
].join(', ')](child: TSESTree.Node): void {
104-
// selector guarantees this assertion
105-
const node = child.parent as TSESTree.TSNonNullExpression;
106-
107-
let current = child;
108-
while (current) {
109-
switch (current.type) {
110-
case AST_NODE_TYPES.MemberExpression:
111-
if (current.optional) {
112-
// found an optional chain! stop traversing
113-
break;
114-
}
115-
116-
current = current.object;
117-
continue;
118-
119-
case AST_NODE_TYPES.CallExpression:
120-
if (current.optional) {
121-
// found an optional chain! stop traversing
122-
break;
123-
}
124-
125-
current = current.callee;
126-
continue;
127-
128-
default:
129-
// something that's not a ChainElement, which means this is not an optional chain we want to check
130-
return;
131-
}
132-
}
133-
134-
context.report({
135-
node,
136-
messageId: 'noNonNullOptionalChain',
137-
// use a suggestion instead of a fixer, because this can obviously break type checks
138-
suggest: [
139-
{
140-
messageId: 'suggestRemovingNonNull',
141-
fix(fixer): TSESLint.RuleFix {
142-
return fixer.removeRange([node.range[1] - 1, node.range[1]]);
143-
},
144-
},
145-
],
146-
});
147-
},
148-
};
14972
},
15073
});

packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
22
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
3-
import * as semver from 'semver';
4-
import * as ts from 'typescript';
53

64
import * as util from '../util';
75

@@ -13,20 +11,6 @@ type TypeParameterWithConstraint = MakeRequired<
1311
'constraint'
1412
>;
1513

16-
const is3dot5 = semver.satisfies(
17-
ts.version,
18-
`>= 3.5.0 || >= 3.5.1-rc || >= 3.5.0-beta`,
19-
{
20-
includePrerelease: true,
21-
},
22-
);
23-
24-
const is3dot9 =
25-
is3dot5 &&
26-
semver.satisfies(ts.version, `>= 3.9.0 || >= 3.9.1-rc || >= 3.9.0-beta`, {
27-
includePrerelease: true,
28-
});
29-
3014
export default util.createRule({
3115
name: 'no-unnecessary-type-constraint',
3216
meta: {
@@ -46,19 +30,13 @@ export default util.createRule({
4630
},
4731
defaultOptions: [],
4832
create(context) {
49-
if (!is3dot5) {
50-
return {};
51-
}
52-
5333
// In theory, we could use the type checker for more advanced constraint types...
5434
// ...but in practice, these types are rare, and likely not worth requiring type info.
5535
// https://github.com/typescript-eslint/typescript-eslint/pull/2516#discussion_r495731858
56-
const unnecessaryConstraints = is3dot9
57-
? new Map([
58-
[AST_NODE_TYPES.TSAnyKeyword, 'any'],
59-
[AST_NODE_TYPES.TSUnknownKeyword, 'unknown'],
60-
])
61-
: new Map([[AST_NODE_TYPES.TSUnknownKeyword, 'unknown']]);
36+
const unnecessaryConstraints = new Map([
37+
[AST_NODE_TYPES.TSAnyKeyword, 'any'],
38+
[AST_NODE_TYPES.TSUnknownKeyword, 'unknown'],
39+
]);
6240

6341
const inJsx = context.getFilename().toLowerCase().endsWith('tsx');
6442
const source = context.getSourceCode();

packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ ruleTester.run('no-non-null-asserted-optional-chain', rule, {
1717
'foo?.bar();',
1818
'(foo?.bar).baz!;',
1919
'(foo?.bar()).baz!;',
20-
// Valid as of 3.9
2120
'foo?.bar!.baz;',
2221
'foo?.bar!();',
2322
"foo?.['bar']!.baz;",

packages/typescript-estree/src/convert.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import type {
3333
import type { SemanticOrSyntacticError } from './semantic-or-syntactic-errors';
3434
import type { TSESTree, TSESTreeToTSNode, TSNode } from './ts-estree';
3535
import { AST_NODE_TYPES } from './ts-estree';
36-
import { typescriptVersionIsAtLeast } from './version-check';
3736

3837
const SyntaxKind = ts.SyntaxKind;
3938

@@ -2151,13 +2150,6 @@ export class Converter {
21512150
});
21522151

21532152
case SyntaxKind.NullKeyword: {
2154-
if (!typescriptVersionIsAtLeast['4.0'] && this.inTypeMode) {
2155-
// 4.0 started nesting null types inside a LiteralType node, but we still need to support pre-4.0
2156-
return this.createNode<TSESTree.TSNullKeyword>(node, {
2157-
type: AST_NODE_TYPES.TSNullKeyword,
2158-
});
2159-
}
2160-
21612153
return this.createNode<TSESTree.NullLiteral>(node, {
21622154
type: AST_NODE_TYPES.Literal,
21632155
value: null,
@@ -2769,10 +2761,7 @@ export class Converter {
27692761
});
27702762
}
27712763
case SyntaxKind.LiteralType: {
2772-
if (
2773-
typescriptVersionIsAtLeast['4.0'] &&
2774-
node.literal.kind === SyntaxKind.NullKeyword
2775-
) {
2764+
if (node.literal.kind === SyntaxKind.NullKeyword) {
27762765
// 4.0 started nesting null types inside a LiteralType node
27772766
// but our AST is designed around the old way of null being a keyword
27782767
return this.createNode<TSESTree.TSNullKeyword>(

packages/typescript-estree/src/create-program/createWatchProgram.ts

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import debug from 'debug';
22
import fs from 'fs';
3-
import semver from 'semver';
43
import * as ts from 'typescript';
54

65
import type { ParseSettings } from '../parseSettings';
@@ -259,10 +258,6 @@ function getProgramsForProjects(parseSettings: ParseSettings): ts.Program[] {
259258
return results;
260259
}
261260

262-
const isRunningNoTimeoutFix = semver.satisfies(ts.version, '>=3.9.0-beta', {
263-
includePrerelease: true,
264-
});
265-
266261
function createWatchProgram(
267262
tsconfigPath: string,
268263
parseSettings: ParseSettings,
@@ -373,34 +368,9 @@ function createWatchProgram(
373368

374369
// Since we don't want to asynchronously update program we want to disable timeout methods
375370
// So any changes in the program will be delayed and updated when getProgram is called on watch
376-
let callback: (() => void) | undefined;
377-
if (isRunningNoTimeoutFix) {
378-
watchCompilerHost.setTimeout = undefined;
379-
watchCompilerHost.clearTimeout = undefined;
380-
} else {
381-
log('Running without timeout fix');
382-
// But because of https://github.com/microsoft/TypeScript/pull/37308 we cannot just set it to undefined
383-
// instead save it and call before getProgram is called
384-
watchCompilerHost.setTimeout = (cb, _ms, ...args: unknown[]): unknown => {
385-
callback = cb.bind(/*this*/ undefined, ...args);
386-
return callback;
387-
};
388-
watchCompilerHost.clearTimeout = (): void => {
389-
callback = undefined;
390-
};
391-
}
392-
const watch = ts.createWatchProgram(watchCompilerHost);
393-
if (!isRunningNoTimeoutFix) {
394-
const originalGetProgram = watch.getProgram;
395-
watch.getProgram = (): ts.BuilderProgram => {
396-
if (callback) {
397-
callback();
398-
}
399-
callback = undefined;
400-
return originalGetProgram.call(watch);
401-
};
402-
}
403-
return watch;
371+
watchCompilerHost.setTimeout = undefined;
372+
watchCompilerHost.clearTimeout = undefined;
373+
return ts.createWatchProgram(watchCompilerHost);
404374
}
405375

406376
function hasTSConfigChanged(tsconfigPath: CanonicalPath): boolean {

packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { ParseSettings } from './index';
66
* This needs to be kept in sync with the top-level README.md in the
77
* typescript-eslint monorepo
88
*/
9-
const SUPPORTED_TYPESCRIPT_VERSIONS = '>=3.3.1 <5.0.0';
9+
const SUPPORTED_TYPESCRIPT_VERSIONS = '>=4.2.4 <5.0.0';
1010

1111
/*
1212
* The semver package will ignore prerelease ranges, and we don't want to explicitly document every one

packages/typescript-estree/src/version-check.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,16 @@ function semverCheck(version: string): boolean {
1212
}
1313

1414
const versions = [
15-
'3.7',
16-
'3.8',
17-
'3.9',
18-
'4.0',
19-
'4.1',
15+
//
2016
'4.2',
2117
'4.3',
2218
'4.4',
2319
'4.5',
2420
'4.6',
2521
'4.7',
2622
'4.8',
23+
'4.9',
24+
'5.0',
2725
] as const;
2826
type Versions = typeof versions extends ArrayLike<infer U> ? U : never;
2927

yarn.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6969,7 +6969,7 @@ eslint-plugin-simple-import-sort@^8.0.0:
69696969
resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz#9d9a2372b0606e999ea841b10458a370a6ccc160"
69706970
integrity sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==
69716971

6972-
eslint-scope@5.1.1:
6972+
eslint-scope@5.1.1, eslint-scope@^5.1.1:
69736973
version "5.1.1"
69746974
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
69756975
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
@@ -13627,7 +13627,7 @@ typedarray@^0.0.6:
1362713627
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
1362813628
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
1362913629

13630-
typescript@*, "typescript@>=3.3.1 <5.0.0", "typescript@^3 || ^4", typescript@next, typescript@~4.8.4, typescript@~4.9.3:
13630+
typescript@*, "typescript@>=4.2.4 <5.0.0", "typescript@^3 || ^4", typescript@next, typescript@~4.8.4, typescript@~4.9.3:
1363113631
version "4.9.3"
1363213632
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
1363313633
integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==

0 commit comments

Comments
 (0)