Skip to content

chore: finish enabling no-unnecessary-condition internally #8004

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

Merged
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
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ module.exports = {
'deprecation/deprecation': 'error',

// TODO(#7338): Investigate enabling these soon ✨
'@typescript-eslint/no-unnecessary-condition': 'off',
'@typescript-eslint/no-dynamic-delete': 'off',
'@typescript-eslint/prefer-nullish-coalescing': 'off',

Expand Down Expand Up @@ -85,6 +84,11 @@ module.exports = {
],
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
'no-constant-condition': 'off',
'@typescript-eslint/no-unnecessary-condition': [
'error',
{ allowConstantLoopConditions: true },
],
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/prefer-literal-enum-member': [
'error',
Expand Down
13 changes: 11 additions & 2 deletions packages/ast-spec/tests/util/serializers/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type { NewPlugin } from 'pretty-format';
import type * as TSESTree from '../../../src';
import { AST_NODE_TYPES } from '../../../src';

function sortKeys(node: TSESTree.Node): (keyof typeof node)[] {
function sortKeys<Node extends TSESTree.Node>(
node: Node,
): (keyof typeof node)[] {
const keySet = new Set(Object.keys(node));

// type place as first key
Expand Down Expand Up @@ -39,7 +41,14 @@ const serializer: NewPlugin = {
test(val: unknown) {
return isObject(val) && hasValidType(val.type);
},
serialize(node: TSESTree.Node, config, indentation, depth, refs, printer) {
serialize(
node: TSESTree.Node & Record<string, unknown>,
config,
indentation,
depth,
refs,
printer,
) {
const keys = sortKeys(node);
const type = node.type;
const loc = node.loc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ export default createRule<Options, MessageIds>({
} catch (ex) {
// ex instanceof Error is false as of @prettier/sync@0.3.0, as is ex instanceof SyntaxError
if (
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
(ex as Partial<Error> | undefined)?.constructor?.name !==
'SyntaxError'
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export default createRule<Options, MessageIds>({
ExportNamedDeclaration(node: TSESTree.ExportNamedDeclaration): void {
// Coerce the source into a string for use as a lookup entry.
const source = getSourceFromExport(node) ?? 'undefined';
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
Copy link
Member

Choose a reason for hiding this comment

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

This is the old issue we've got filed right where TS is giving the wrong type for logical assignment operators?

If yes - Oof we should prioritise this #6762

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah :/

const sourceExports = (sourceExportsMap[source] ||= {
source,
reportValueExports: [],
Expand Down
6 changes: 4 additions & 2 deletions packages/eslint-plugin/src/rules/consistent-type-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export default createRule<Options, MessageIds>({
ImportDeclaration(node): void {
const source = node.source.value;
// sourceImports is the object containing all the specifics for a particular import source, type or value
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
sourceImportsMap[source] ??= {
source,
reportValueImports: [], // if there is a mismatch where type importKind but value specifiers
Expand Down Expand Up @@ -194,8 +195,9 @@ export default createRule<Options, MessageIds>({
}
}
if (ref.isValueReference) {
let parent: TSESTree.Node | undefined =
ref.identifier.parent;
let parent = ref.identifier.parent as
| TSESTree.Node
| undefined;
let child: TSESTree.Node = ref.identifier;
while (parent) {
switch (parent.type) {
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-extra-parens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ export default createRule<Options, MessageIds>({
}
},
};
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (rules.ForInStatement && rules.ForOfStatement) {
overrides.ForInStatement = function (node): void {
if (isTypeAssertion(node.right)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/no-shadow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ export default createRule<Options, MessageIds>({
return false;
}

let node: TSESTree.Node | undefined = outerDef.name;
let node = outerDef.name as TSESTree.Node | undefined;
const location = callExpression.range[1];

while (node) {
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/prefer-readonly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export default createRule<Options, MessageIds>({
function isDestructuringAssignment(
node: ts.PropertyAccessExpression,
): boolean {
let current: ts.Node = node.parent;
let current = node.parent as ts.Node | undefined;

while (current) {
const parent = current.parent;
Expand Down
8 changes: 4 additions & 4 deletions packages/eslint-plugin/src/rules/return-await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default createRule({
}

function inTry(node: ts.Node): boolean {
let ancestor = node.parent;
let ancestor = node.parent as ts.Node | undefined;

while (ancestor && !ts.isFunctionLike(ancestor)) {
if (ts.isTryStatement(ancestor)) {
Expand All @@ -85,7 +85,7 @@ export default createRule({
}

function inCatch(node: ts.Node): boolean {
let ancestor = node.parent;
let ancestor = node.parent as ts.Node | undefined;

while (ancestor && !ts.isFunctionLike(ancestor)) {
if (ts.isCatchClause(ancestor)) {
Expand All @@ -99,7 +99,7 @@ export default createRule({
}

function isReturnPromiseInFinally(node: ts.Node): boolean {
let ancestor = node.parent;
let ancestor = node.parent as ts.Node | undefined;

while (ancestor && !ts.isFunctionLike(ancestor)) {
if (
Expand All @@ -116,7 +116,7 @@ export default createRule({
}

function hasFinallyBlock(node: ts.Node): boolean {
let ancestor = node.parent;
let ancestor = node.parent as ts.Node | undefined;

while (ancestor && !ts.isFunctionLike(ancestor)) {
if (ts.isTryStatement(ancestor)) {
Expand Down
8 changes: 4 additions & 4 deletions packages/eslint-plugin/src/rules/unified-signatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ export default createRule<Options, MessageIds>({
const isTypeParameter = getIsTypeParameter(typeParameters);
for (const overloads of signatures) {
forEachPair(overloads, (a, b) => {
const signature0 = (a as MethodDefinition).value ?? a;
const signature1 = (b as MethodDefinition).value ?? b;
const signature0 = (a as Partial<MethodDefinition>).value ?? a;
const signature1 = (b as Partial<MethodDefinition>).value ?? b;

const unify = compareSignatures(
signature0,
signature1,
signature0 as SignatureDefinition,
signature1 as SignatureDefinition,
isTypeParameter,
);
if (unify !== undefined) {
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/util/getThisExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
export function getThisExpression(
node: TSESTree.Node,
): TSESTree.ThisExpression | undefined {
while (node) {
while (true) {
if (node.type === AST_NODE_TYPES.CallExpression) {
node = node.callee;
} else if (node.type === AST_NODE_TYPES.ThisExpression) {
Expand Down
1 change: 1 addition & 0 deletions packages/rule-tester/src/RuleTester.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
Copy link
Member

Choose a reason for hiding this comment

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

was there a bunch of errors here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, 9 of them. Mostly around type safety checks on user-provided parameters. E.g. config == null:

    if (typeof config !== 'object' || config == null) {
      throw new TypeError(
        'RuleTester.setDefaultConfig: config must be an object',
      );
    }

// Forked from https://github.com/eslint/eslint/blob/ad9dd6a933fd098a0d99c6a9aa059850535c23ee/lib/rule-tester/rule-tester.js

import assert from 'node:assert';
Expand Down
1 change: 1 addition & 0 deletions packages/scope-manager/src/referencer/Referencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class Referencer extends Visitor {
private populateGlobalsFromLib(globalScope: GlobalScope): void {
for (const lib of this.#lib) {
const variables = TSLibraries[lib];
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
/* istanbul ignore if */ if (!variables) {
throw new Error(`Invalid value for lib provided: ${lib}`);
}
Expand Down
1 change: 1 addition & 0 deletions packages/scope-manager/src/referencer/TypeVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class TypeVisitor extends Visitor {
});

// there are a few special cases where the type annotation is owned by the parameter, not the pattern
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!didVisitAnnotation && 'typeAnnotation' in param) {
this.visit(param.typeAnnotation);
}
Expand Down
1 change: 1 addition & 0 deletions packages/type-utils/src/getTypeArguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export function getTypeArguments(
checker: ts.TypeChecker,
): readonly ts.Type[] {
// getTypeArguments was only added in TS3.7
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (checker.getTypeArguments) {
return checker.getTypeArguments(type);
}
Expand Down
1 change: 1 addition & 0 deletions packages/typescript-estree/src/convert.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
// There's lots of funny stuff due to the typing of ts.Node
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access */
import * as ts from 'typescript';
Expand Down
2 changes: 2 additions & 0 deletions packages/typescript-estree/src/create-program/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type CanonicalPath = string & { __brand: unknown };

// typescript doesn't provide a ts.sys implementation for browser environments
const useCaseSensitiveFileNames =
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
ts.sys !== undefined ? ts.sys.useCaseSensitiveFileNames : true;
const correctPathCasing = useCaseSensitiveFileNames
? (filePath: string): string => filePath
Expand Down Expand Up @@ -118,6 +119,7 @@ function getAstFromProgram(
*/
function createHash(content: string): string {
// No ts.sys in browser environments.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (ts.sys?.createHash) {
return ts.sys.createHash(content);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ function createProgramFromConfigFile(
configFile: string,
projectDirectory?: string,
): ts.Program {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (ts.sys === undefined) {
throw new Error(
'`createProgramFromConfigFile` is only supported in a Node-like environment.',
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript-estree/src/node-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ export function findFirstMatchingAncestor(
if (predicate(current)) {
return current;
}
current = current.parent;
current = current.parent as ts.Node | undefined;
}
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@ let TSSERVER_PROJECT_SERVICE: TypeScriptProjectService | null = null;

// NOTE - we intentionally use "unnecessary" `?.` here because in TS<5.3 this enum doesn't exist
// This object exists so we can centralize these for tracking and so we don't proliferate these across the file
// https://github.com/microsoft/TypeScript/issues/56579
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
const JSDocParsingMode = {
ParseAll: ts.JSDocParsingMode?.ParseAll,
ParseNone: ts.JSDocParsingMode?.ParseNone,
ParseForTypeErrors: ts.JSDocParsingMode?.ParseForTypeErrors,
ParseForTypeInfo: ts.JSDocParsingMode?.ParseForTypeInfo,
} as const;
/* eslint-enable @typescript-eslint/no-unnecessary-condition */

export function createParseSettings(
code: ts.SourceFile | string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export function warnAboutTSVersion(

if (
passedLoggerFn ||
// See https://github.com/typescript-eslint/typescript-eslint/issues/7896
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
(typeof process === 'undefined' ? false : process.stdout?.isTTY)
) {
const border = '=============';
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/eslint-utils/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Wrappers around ESLint's deprecation of existing methods
// We'll be able to drop them once we no longer support ESLint <8.40.0.
/* eslint-disable deprecation/deprecation */
/* eslint-disable @typescript-eslint/no-unnecessary-condition, deprecation/deprecation */
import type { Scope, SourceCode } from '../ts-eslint';
import type { RuleContext } from '../ts-eslint/Rule';
import type { TSESTree } from '../ts-estree';
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/eslint-utils/getParserServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function getParserServices(
if (
// eslint-disable-next-line deprecation/deprecation -- TODO - support for ESLint v9 with backwards-compatible support for ESLint v8
context.parserServices?.esTreeNodeToTSNodeMap == null ||
// eslint-disable-next-line deprecation/deprecation -- TODO - support for ESLint v9 with backwards-compatible support for ESLint v8
// eslint-disable-next-line deprecation/deprecation, @typescript-eslint/no-unnecessary-condition -- TODO - support for ESLint v9 with backwards-compatible support for ESLint v8
context.parserServices.tsNodeToESTreeNodeMap == null
) {
throw new Error(ERROR_MESSAGE);
Expand Down
2 changes: 2 additions & 0 deletions packages/website/src/components/Playground.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// See https://github.com/typescript-eslint/typescript-eslint/issues/7630.
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
import { useWindowSize } from '@docusaurus/theme-common';
import clsx from 'clsx';
import type * as ESQuery from 'esquery';
Expand Down
1 change: 1 addition & 0 deletions packages/website/src/components/ast/ASTViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface ASTViewerProps {

function tryToApplyFilter<T>(value: T, filter?: ESQuery.Selector): T | T[] {
try {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (window.esquery && filter) {
// @ts-expect-error - esquery requires js ast types
return window.esquery.match(value, filter);
Expand Down
4 changes: 2 additions & 2 deletions packages/website/src/components/ast/selectedRange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function findInObject(
visited: Set<unknown>,
): {
key: string[];
value: object;
value: unknown;
} | null {
const children = Object.entries(iter);
for (const [name, child] of children) {
Expand Down Expand Up @@ -73,7 +73,7 @@ export function findSelectionPath(
): { path: string[]; node: object | null } {
const nodePath = ['ast'];
const visited = new Set<unknown>();
let currentNode: object | null = node;
let currentNode: unknown = node;
while (currentNode) {
// infinite loop guard
if (visited.has(currentNode)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function ConfigTypeScript(props: ConfigTypeScriptProps): React.JSX.Element {
getTypescriptOptions().reduce<Record<string, ConfigOptionsType>>(
(group, item) => {
const category = item.category!.message;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
group[category] ??= {
heading: category,
fields: [],
Expand Down
2 changes: 2 additions & 0 deletions packages/website/src/components/linter/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const defaultParseSettings: ParseSettings = {
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: false,
extraFileExtensions: [],
filePath: '',
// JSDocParsingMode was added in TS 5.3.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
jsDocParsingMode: window.ts?.JSDocParsingMode?.ParseAll,
jsx: true,
loc: true,
Expand Down
42 changes: 20 additions & 22 deletions packages/website/src/components/linter/createLinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,29 +76,27 @@ export function createLinter(
const triggerLint = (filename: string): void => {
console.info('[Editor] linting triggered for file', filename);
const code = system.readFile(filename) ?? '\n';
if (code != null) {
try {
const messages = linter.verify(code, eslintConfig, filename);
onLint.trigger(filename, messages);
} catch (e) {
const lintMessage: Linter.LintMessage = {
source: 'eslint',
ruleId: '',
severity: 2,
nodeType: '',
column: 1,
line: 1,
message: String(e instanceof Error ? e.stack : e),
};
if (typeof e === 'object' && e && 'currentNode' in e) {
const node = e.currentNode as TSESTree.Node;
lintMessage.column = node.loc.start.column + 1;
lintMessage.line = node.loc.start.line;
lintMessage.endColumn = node.loc.end.column + 1;
lintMessage.endLine = node.loc.end.line;
}
onLint.trigger(filename, [lintMessage]);
try {
const messages = linter.verify(code, eslintConfig, filename);
onLint.trigger(filename, messages);
} catch (e) {
const lintMessage: Linter.LintMessage = {
source: 'eslint',
ruleId: '',
severity: 2,
nodeType: '',
column: 1,
line: 1,
message: String(e instanceof Error ? e.stack : e),
};
if (typeof e === 'object' && e && 'currentNode' in e) {
const node = e.currentNode as TSESTree.Node;
lintMessage.column = node.loc.start.column + 1;
lintMessage.line = node.loc.start.line;
lintMessage.endColumn = node.loc.end.column + 1;
lintMessage.endLine = node.loc.end.line;
}
onLint.trigger(filename, [lintMessage]);
}
};

Expand Down
1 change: 1 addition & 0 deletions packages/website/src/components/linter/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export function parseMarkers(
? 'TypeScript'
: marker.owner;

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!result[group]) {
result[group] = {
group: group,
Expand Down
Loading