From 6f1022d6147b9307edc060317360e63abde445f1 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 4 Feb 2026 07:54:51 -0800 Subject: [PATCH] Fix exhaustive deps bug with flow type casting. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: I noticed there's a bug where the lint will recognize the type on a cast annotation as a missing dependency; ``` function MyComponent() { type ColumnKey = 'id' | 'name'; type Item = {id: string, name: string}; const columns = useMemo( () => [ { type: 'text', key: 'id', } as TextColumn, ^^^^^^^^ here ], [], ); } ``` This is due to the AST of AsExressions being something like: AsExpression └── typeAnnotation: GenericTypeAnnotation └── typeParameters: TypeParameterInstantiation └── params[0]: GenericTypeAnnotation └── id: Identifier (name: "ColumnKey") Where `ColumnKey` never has a TypeParameter Annotation. So we need to consider it to be a flow type due to it belonging to a GenericTypeAnnotation Test Plan: Added unit tests Before: Test Suites: 1 failed, 2 passed, 3 total Tests: 2 failed, 5065 passed, 5067 total Snapshots: 0 total Time: 16.517 s Ran all test suites. error Command failed with exit code 1. After: ``` PASS __tests__/ReactCompilerRuleTypescript-test.ts PASS __tests__/ESLintRulesOfHooks-test.js (6.192 s) PASS __tests__/ESLintRuleExhaustiveDeps-test.js (9.97 s) Test Suites: 3 passed, 3 total Tests: 5067 passed, 5067 total Snapshots: 0 total Time: 10.21 s, estimated 11 s Ran all test suites. ✨ Done in 12.66s. ``` --- .../ESLintRuleExhaustiveDeps-test.js | 19 +++++++++++++++++++ .../src/rules/ExhaustiveDeps.ts | 11 +++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js index b479ce4852..29e956d314 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js @@ -7913,6 +7913,25 @@ const testsFlow = { } `, }, + // Flow type aliases in type assertions should not be flagged as missing dependencies + { + code: normalizeIndent` + function MyComponent() { + type ColumnKey = 'id' | 'name'; + type Item = {id: string, name: string}; + + const columns = useMemo( + () => [ + { + type: 'text', + key: 'id', + } as TextColumn, + ], + [], + ); + } + `, + }, ], invalid: [ { diff --git a/packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts b/packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts index 05321ffb46..6b79068060 100644 --- a/packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts +++ b/packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts @@ -21,7 +21,7 @@ import type { VariableDeclarator, } from 'estree'; -import { getAdditionalEffectHooksFromSettings } from '../shared/Utils'; +import {getAdditionalEffectHooksFromSettings} from '../shared/Utils'; type DeclaredDependency = { key: string; @@ -80,7 +80,6 @@ const rule = { const rawOptions = context.options && context.options[0]; const settings = context.settings || {}; - // Parse the `additionalHooks` regex. // Use rule-level additionalHooks if provided, otherwise fall back to settings const additionalHooks = @@ -565,8 +564,12 @@ const rule = { continue; } // Ignore Flow type parameters - // @ts-expect-error We don't have flow types - if (def.type === 'TypeParameter') { + if ( + // @ts-expect-error We don't have flow types + def.type === 'TypeParameter' || + // @ts-expect-error Flow-specific AST node type + dependencyNode.parent?.type === 'GenericTypeAnnotation' + ) { continue; }