diff --git a/README.md b/README.md index 93bee2f66dc..511c8dc54cf 100644 --- a/README.md +++ b/README.md @@ -51,23 +51,37 @@ The latest version under the `canary` tag **(latest commit to `main`)** is: ### Supported TypeScript Version -**The version range of TypeScript currently supported by this parser is `>=3.3.1 <5.0.0`.** +**The version range of TypeScript currently supported by this parser is `>=4.2.0 <5.0.0`.** -These versions are what we test against. +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. -We will always endeavor to support the latest stable version of TypeScript. -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. -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. +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_**. + +#### Supporting New TypeScript Releases + +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. + +In terms of what versions we support: + +- We do not support the `beta` releases. +- We _generally_ do not officially support the `rc` releases. +- We endeavor to support the latest stable TypeScript versions as soon as possible after the release. + +Generally we will begin working on supporting the next release when the `rc` version is released. + +#### Version Warning Logs Note that our packages have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript. -If you use a non-supported version of TypeScript, the parser will log a warning to the console. +However if you use a non-supported version of TypeScript, the parser will log a warning to the console. 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/). **Please ensure that you are using a supported version before submitting any issues/bug reports.** ### Supported ESLint Version +We endeavour to support the latest stable ESLint versions as soon as possible after the release. + See the value of `eslint` declared in `@typescript-eslint/eslint-plugin`'s [package.json](./packages/eslint-plugin/package.json). ### Supported Node Version diff --git a/package.json b/package.json index d3ff24f36a6..76f4f0f2bea 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "tmp": "^0.2.1", "ts-node": "^10.7.0", "tslint": "^6.1.3", - "typescript": ">=3.3.1 <5.0.0" + "typescript": ">=4.2.4 <5.0.0" }, "resolutions": { "typescript": "~4.9.3", diff --git a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts index d63b3ad43e3..27675423e11 100644 --- a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts @@ -1,18 +1,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; -import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as semver from 'semver'; -import * as ts from 'typescript'; import * as util from '../util'; -const is3dot9 = semver.satisfies( - ts.version, - `>= 3.9.0 || >= 3.9.1-rc || >= 3.9.0-beta`, - { - includePrerelease: true, - }, -); - export default util.createRule({ name: 'no-non-null-asserted-optional-chain', meta: { @@ -32,16 +21,7 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - // TS3.9 made a breaking change to how non-null works with optional chains. - // Pre-3.9, `x?.y!.z` means `(x?.y).z` - i.e. it essentially scrubbed the optionality from the chain - // 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`. - // This means that for > 3.9, x?.y!.z is valid! - // - // NOTE: these cases are still invalid for 3.9: - // - x?.y.z! - // - (x?.y)!.z - - const baseSelectors = { + return { // non-nulling a wrapped chain will scrub all nulls introduced by the chain // (x?.y)! // (x?.())! @@ -89,62 +69,5 @@ export default util.createRule({ }); }, }; - - if (is3dot9) { - return baseSelectors; - } - - return { - ...baseSelectors, - [[ - // > :not(ChainExpression) because that case is handled by a previous selector - 'MemberExpression > TSNonNullExpression.object > :not(ChainExpression)', - 'CallExpression > TSNonNullExpression.callee > :not(ChainExpression)', - ].join(', ')](child: TSESTree.Node): void { - // selector guarantees this assertion - const node = child.parent as TSESTree.TSNonNullExpression; - - let current = child; - while (current) { - switch (current.type) { - case AST_NODE_TYPES.MemberExpression: - if (current.optional) { - // found an optional chain! stop traversing - break; - } - - current = current.object; - continue; - - case AST_NODE_TYPES.CallExpression: - if (current.optional) { - // found an optional chain! stop traversing - break; - } - - current = current.callee; - continue; - - default: - // something that's not a ChainElement, which means this is not an optional chain we want to check - return; - } - } - - context.report({ - node, - messageId: 'noNonNullOptionalChain', - // use a suggestion instead of a fixer, because this can obviously break type checks - suggest: [ - { - messageId: 'suggestRemovingNonNull', - fix(fixer): TSESLint.RuleFix { - return fixer.removeRange([node.range[1] - 1, node.range[1]]); - }, - }, - ], - }); - }, - }; }, }); diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts index a337200a9a7..4e4547e2ffb 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-constraint.ts @@ -1,7 +1,5 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import * as semver from 'semver'; -import * as ts from 'typescript'; import * as util from '../util'; @@ -13,20 +11,6 @@ type TypeParameterWithConstraint = MakeRequired< 'constraint' >; -const is3dot5 = semver.satisfies( - ts.version, - `>= 3.5.0 || >= 3.5.1-rc || >= 3.5.0-beta`, - { - includePrerelease: true, - }, -); - -const is3dot9 = - is3dot5 && - semver.satisfies(ts.version, `>= 3.9.0 || >= 3.9.1-rc || >= 3.9.0-beta`, { - includePrerelease: true, - }); - export default util.createRule({ name: 'no-unnecessary-type-constraint', meta: { @@ -46,19 +30,13 @@ export default util.createRule({ }, defaultOptions: [], create(context) { - if (!is3dot5) { - return {}; - } - // In theory, we could use the type checker for more advanced constraint types... // ...but in practice, these types are rare, and likely not worth requiring type info. // https://github.com/typescript-eslint/typescript-eslint/pull/2516#discussion_r495731858 - const unnecessaryConstraints = is3dot9 - ? new Map([ - [AST_NODE_TYPES.TSAnyKeyword, 'any'], - [AST_NODE_TYPES.TSUnknownKeyword, 'unknown'], - ]) - : new Map([[AST_NODE_TYPES.TSUnknownKeyword, 'unknown']]); + const unnecessaryConstraints = new Map([ + [AST_NODE_TYPES.TSAnyKeyword, 'any'], + [AST_NODE_TYPES.TSUnknownKeyword, 'unknown'], + ]); const inJsx = context.getFilename().toLowerCase().endsWith('tsx'); const source = context.getSourceCode(); diff --git a/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts index 5f7caabc5b0..399c6b73488 100644 --- a/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts @@ -17,7 +17,6 @@ ruleTester.run('no-non-null-asserted-optional-chain', rule, { 'foo?.bar();', '(foo?.bar).baz!;', '(foo?.bar()).baz!;', - // Valid as of 3.9 'foo?.bar!.baz;', 'foo?.bar!();', "foo?.['bar']!.baz;", diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index b2d5a671986..2bcf03e6193 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -33,7 +33,6 @@ import type { import type { SemanticOrSyntacticError } from './semantic-or-syntactic-errors'; import type { TSESTree, TSESTreeToTSNode, TSNode } from './ts-estree'; import { AST_NODE_TYPES } from './ts-estree'; -import { typescriptVersionIsAtLeast } from './version-check'; const SyntaxKind = ts.SyntaxKind; @@ -2151,13 +2150,6 @@ export class Converter { }); case SyntaxKind.NullKeyword: { - if (!typescriptVersionIsAtLeast['4.0'] && this.inTypeMode) { - // 4.0 started nesting null types inside a LiteralType node, but we still need to support pre-4.0 - return this.createNode(node, { - type: AST_NODE_TYPES.TSNullKeyword, - }); - } - return this.createNode(node, { type: AST_NODE_TYPES.Literal, value: null, @@ -2769,10 +2761,7 @@ export class Converter { }); } case SyntaxKind.LiteralType: { - if ( - typescriptVersionIsAtLeast['4.0'] && - node.literal.kind === SyntaxKind.NullKeyword - ) { + if (node.literal.kind === SyntaxKind.NullKeyword) { // 4.0 started nesting null types inside a LiteralType node // but our AST is designed around the old way of null being a keyword return this.createNode( diff --git a/packages/typescript-estree/src/create-program/createWatchProgram.ts b/packages/typescript-estree/src/create-program/createWatchProgram.ts index d17835fff3c..96687206f7f 100644 --- a/packages/typescript-estree/src/create-program/createWatchProgram.ts +++ b/packages/typescript-estree/src/create-program/createWatchProgram.ts @@ -1,6 +1,5 @@ import debug from 'debug'; import fs from 'fs'; -import semver from 'semver'; import * as ts from 'typescript'; import type { ParseSettings } from '../parseSettings'; @@ -259,10 +258,6 @@ function getProgramsForProjects(parseSettings: ParseSettings): ts.Program[] { return results; } -const isRunningNoTimeoutFix = semver.satisfies(ts.version, '>=3.9.0-beta', { - includePrerelease: true, -}); - function createWatchProgram( tsconfigPath: string, parseSettings: ParseSettings, @@ -373,34 +368,9 @@ function createWatchProgram( // Since we don't want to asynchronously update program we want to disable timeout methods // So any changes in the program will be delayed and updated when getProgram is called on watch - let callback: (() => void) | undefined; - if (isRunningNoTimeoutFix) { - watchCompilerHost.setTimeout = undefined; - watchCompilerHost.clearTimeout = undefined; - } else { - log('Running without timeout fix'); - // But because of https://github.com/microsoft/TypeScript/pull/37308 we cannot just set it to undefined - // instead save it and call before getProgram is called - watchCompilerHost.setTimeout = (cb, _ms, ...args: unknown[]): unknown => { - callback = cb.bind(/*this*/ undefined, ...args); - return callback; - }; - watchCompilerHost.clearTimeout = (): void => { - callback = undefined; - }; - } - const watch = ts.createWatchProgram(watchCompilerHost); - if (!isRunningNoTimeoutFix) { - const originalGetProgram = watch.getProgram; - watch.getProgram = (): ts.BuilderProgram => { - if (callback) { - callback(); - } - callback = undefined; - return originalGetProgram.call(watch); - }; - } - return watch; + watchCompilerHost.setTimeout = undefined; + watchCompilerHost.clearTimeout = undefined; + return ts.createWatchProgram(watchCompilerHost); } function hasTSConfigChanged(tsconfigPath: CanonicalPath): boolean { diff --git a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts b/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts index ad9a74157d6..75c88ed0c97 100644 --- a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts +++ b/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts @@ -6,7 +6,7 @@ import type { ParseSettings } from './index'; * This needs to be kept in sync with the top-level README.md in the * typescript-eslint monorepo */ -const SUPPORTED_TYPESCRIPT_VERSIONS = '>=3.3.1 <5.0.0'; +const SUPPORTED_TYPESCRIPT_VERSIONS = '>=4.2.4 <5.0.0'; /* * The semver package will ignore prerelease ranges, and we don't want to explicitly document every one diff --git a/packages/typescript-estree/src/version-check.ts b/packages/typescript-estree/src/version-check.ts index 194636cb587..41913041301 100644 --- a/packages/typescript-estree/src/version-check.ts +++ b/packages/typescript-estree/src/version-check.ts @@ -12,11 +12,7 @@ function semverCheck(version: string): boolean { } const versions = [ - '3.7', - '3.8', - '3.9', - '4.0', - '4.1', + // '4.2', '4.3', '4.4', @@ -24,6 +20,8 @@ const versions = [ '4.6', '4.7', '4.8', + '4.9', + '5.0', ] as const; type Versions = typeof versions extends ArrayLike ? U : never; diff --git a/yarn.lock b/yarn.lock index 7cafafcd627..7754c213a4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6969,7 +6969,7 @@ eslint-plugin-simple-import-sort@^8.0.0: resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz#9d9a2372b0606e999ea841b10458a370a6ccc160" integrity sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw== -eslint-scope@5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -13627,7 +13627,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@*, "typescript@>=3.3.1 <5.0.0", "typescript@^3 || ^4", typescript@next, typescript@~4.8.4, typescript@~4.9.3: +typescript@*, "typescript@>=4.2.4 <5.0.0", "typescript@^3 || ^4", typescript@next, typescript@~4.8.4, typescript@~4.9.3: version "4.9.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==