@@ -504,7 +504,13 @@ impl Rule for ExhaustiveDeps {
504504 return false ;
505505 }
506506
507- if !is_identifier_a_dependency ( dep. name , dep. reference_id , ctx, component_scope_id) {
507+ if !is_identifier_a_dependency (
508+ dep. name ,
509+ dep. reference_id ,
510+ dep. span ,
511+ ctx,
512+ component_scope_id,
513+ ) {
508514 return false ;
509515 }
510516 true
@@ -779,6 +785,7 @@ fn concat_members<'a, 'b>(
779785fn is_identifier_a_dependency < ' a > (
780786 ident_name : Atom < ' a > ,
781787 ident_reference_id : ReferenceId ,
788+ ident_span : Span ,
782789 ctx : & ' _ LintContext < ' a > ,
783790 component_scope_id : ScopeId ,
784791) -> bool {
@@ -835,6 +842,17 @@ fn is_identifier_a_dependency<'a>(
835842 return false ;
836843 }
837844
845+ // Using a declaration recursively is ok
846+ // ```tsx
847+ // function MyComponent() {
848+ // const recursive = useCallback((n: number): number => (n <= 0 ? 0 : n + recursive(n - 1)), []);
849+ // return recursive
850+ // }
851+ // ```
852+ if declaration. span ( ) . contains_inclusive ( ident_span) {
853+ return false ;
854+ }
855+
838856 true
839857}
840858
@@ -969,7 +987,13 @@ fn is_function_stable<'a, 'b>(
969987
970988 deps. iter ( ) . all ( |dep| {
971989 dep. symbol_id . zip ( function_symbol_id) . is_none_or ( |( l, r) | l != r)
972- && !is_identifier_a_dependency ( dep. name , dep. reference_id , ctx, component_scope_id)
990+ && !is_identifier_a_dependency (
991+ dep. name ,
992+ dep. reference_id ,
993+ dep. span ,
994+ ctx,
995+ component_scope_id,
996+ )
973997 } )
974998}
975999
@@ -2159,6 +2183,7 @@ fn test() {
21592183 return null;
21602184}
21612185"# ,
2186+ r"function MyComponent() { const recursive = useCallback((n: number): number => (n <= 0 ? 0 : n + recursive(n - 1)), []); return recursive }" ,
21622187 ] ;
21632188
21642189 let fail = vec ! [
0 commit comments