Skip to content

Require Named Effect Functions

Error
small-rules/require-named-effect-functions

Enforce named effect functions for better debuggability. Prevents inline arrow functions in useEffect and similar hooks.

Diagnostic Messages

anonymousFunction
Anonymous function passed to {{hook}}. debug.info returns empty string for anonymous functions, making stack traces useless for debugging. Extract to: function effectName() { ... } then pass effectName.
arrowFunction
Arrow function passed to {{hook}}. Arrow functions have no debug name and create new instances each render. Extract to: function effectName() { ... } then pass effectName.
asyncAnonymousFunction
Async anonymous function in {{hook}}. Two issues: (1) no debug name makes stack traces useless, (2) async effects require cancellation logic for unmount. Extract to: async function effectName() { ... } with cleanup.
asyncArrowFunction
Async arrow function in {{hook}}. Two issues: (1) arrow functions have no debug name, (2) async effects require cancellation logic. Extract to: async function effectName() { ... } with cleanup.
asyncFunctionDeclaration
Async function declaration passed to {{hook}}. Async effects require cancellation logic to handle component unmount. Implement cleanup or set allowAsync: true if cancellation is handled.
asyncFunctionExpression
Async function expression in {{hook}}. Async effects require cancellation logic for unmount. Extract to a named async function declaration with cleanup, then pass the reference.
functionExpression
Function expression passed to {{hook}}. Function expressions create new instances each render, breaking referential equality. Extract to: function effectName() { ... } at module or component top-level.
identifierReferencesArrow
{{hook}} receives identifier pointing to arrow function. Arrow functions have no debug name and lack referential stability. Convert to: function effectName() { ... } then pass effectName.
identifierReferencesAsyncArrow
{{hook}} receives identifier pointing to async arrow function. Two issues: (1) no debug name, (2) async effects require cancellation logic. Convert to: async function effectName() { ... } with cleanup.
identifierReferencesAsyncFunction
{{hook}} receives identifier pointing to async function. Async effects require cancellation logic for unmount. Implement cleanup or set allowAsync: true if cancellation is handled.
identifierReferencesCallback
{{hook}} receives identifier from useCallback/useMemo. These hooks return new references when dependencies change, causing unexpected effect re-runs. Use a stable function declaration: function effectName() { ... }

Configuration

This rule accepts one options object after the severity.

environmentOptional

Environment mode: 'roblox-ts' only allows identifiers, 'standard' allows both identifiers and named function expressions

hooksOptional

Hook configuration objects with name and allowAsync settings.

{
"jsPlugins": [
"@pobammer-ts/small-rules"
],
"rules": {
"small-rules/require-named-effect-functions": [
"error",
{
"environment": "roblox-ts",
"hooks": [
{
"allowAsync": false,
"name": "useEffect"
},
{
"allowAsync": false,
"name": "useLayoutEffect"
},
{
"allowAsync": false,
"name": "useInsertionEffect"
}
]
}
]
}
}

Examples

Anonymous effect callback
useEffect(() => {
console.log("effect");
}, []);
Named effect callback
function handleEffect() {
console.log("effect");
}
useEffect(handleEffect, []);