Skip to content

Commit

Permalink
fix(lint): support some of wrapped hook calls in useExhaustiveDepende…
Browse files Browse the repository at this point in the history
…ncies (#4964)

Signed-off-by: Naoki Ikeguchi <[email protected]>
Signed-off-by: Naoki Ikeguchi <[email protected]>
  • Loading branch information
siketyan authored Jan 24, 2025
1 parent 44d3f81 commit e750523
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
biome_js_analyze: patch
---

# Fix #1597, useExhaustiveDependencies now consider React hooks stable within parentheses or type assertions
28 changes: 27 additions & 1 deletion crates/biome_js_analyze/src/react/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ pub fn is_binding_react_stable(
let Some(callee) = declarator
.initializer()
.and_then(|initializer| initializer.expression().ok())
.and_then(|initializer| initializer.as_js_call_expression()?.callee().ok())
.and_then(|initializer| unwrap_to_call_expression(initializer)?.callee().ok())
else {
return false;
};
Expand All @@ -474,6 +474,32 @@ pub fn is_binding_react_stable(
})
}

/// Unwrap the expression to a call expression without changing the result of the expression,
/// such as type assertions.
fn unwrap_to_call_expression(mut expression: AnyJsExpression) -> Option<JsCallExpression> {
loop {
match expression {
AnyJsExpression::JsCallExpression(expr) => return Some(expr),
AnyJsExpression::JsParenthesizedExpression(expr) => {
expression = expr.expression().ok()?;
}
AnyJsExpression::JsSequenceExpression(expr) => {
expression = expr.right().ok()?;
}
AnyJsExpression::TsAsExpression(expr) => {
expression = expr.expression().ok()?;
}
AnyJsExpression::TsSatisfiesExpression(expr) => {
expression = expr.expression().ok()?;
}
AnyJsExpression::TsNonNullAssertionExpression(expr) => {
expression = expr.expression().ok()?;
}
_ => return None,
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* should not generate diagnostics */

import { useEffect } from "react";
import { type MutableRefObject, useEffect, useRef } from "react";

// capturing declarations
function overloaded(s: string): string;
Expand Down Expand Up @@ -46,3 +46,20 @@ export function MyComponent3({ outer }: { outer: string[] }) {
console.log(a)
}, []);
}

// useRef's are still considered as stable even if there's any type assertion
export function MyComponent4() {
const parenthesizedRef = (((useRef())));
const sequenceRef = (doSomething(), useRef());
const nonNullAssertedRef = useRef()!;
const castedRef = useRef() as MutableRefObject<HTMLElement>;
const satisfiedRef = useRef() satisfies MutableRefObject<HTMLElement>;

useEffect(() => {
console.log(parenthesizedRef.current);
console.log(sequenceRef.current);
console.log(nonNullAssertedRef.current);
console.log(castedRef.current.innerHTML);
console.log(satisfiedRef.current.innerHTML);
}, []);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ expression: valid.ts
```ts
/* should not generate diagnostics */

import { useEffect } from "react";
import { type MutableRefObject, useEffect, useRef } from "react";

// capturing declarations
function overloaded(s: string): string;
Expand Down Expand Up @@ -53,6 +53,21 @@ export function MyComponent3({ outer }: { outer: string[] }) {
}, []);
}

```
// useRef's are still considered as stable even if there's any type assertion
export function MyComponent4() {
const parenthesizedRef = (((useRef())));
const sequenceRef = (doSomething(), useRef());
const nonNullAssertedRef = useRef()!;
const castedRef = useRef() as MutableRefObject<HTMLElement>;
const satisfiedRef = useRef() satisfies MutableRefObject<HTMLElement>;

useEffect(() => {
console.log(parenthesizedRef.current);
console.log(sequenceRef.current);
console.log(nonNullAssertedRef.current);
console.log(castedRef.current.innerHTML);
console.log(satisfiedRef.current.innerHTML);
}, []);
}

```

0 comments on commit e750523

Please sign in to comment.