Rule
Don't overuse undocumented anonymous functions.
Large anonymous functions without documentation
are difficult to understand and reuse.
Supported languages: 45+Introduction
Anonymous functions passed as callbacks or event handlers hide their purpose behind implementation details. A 20-line arrow function in a .map() or .filter() forces readers to parse the entire logic to understand what transformation happens. Named functions with descriptive names document intent immediately, and complex logic can be understood by reading the function name before diving into implementation.
Code examples
❌ Non-compliant:
app.get('/users', async (req, res) => {
const users = await db.users.find({});
const processed = users.filter(u => {
const hasActiveSubscription = u.subscriptions?.some(s =>
s.status === 'active' && new Date(s.expiresAt) > new Date()
);
const isVerified = u.emailVerified && u.phoneVerified;
return hasActiveSubscription && isVerified && !u.deleted;
}).map(u => ({
id: u.id,
name: `${u.firstName} ${u.lastName}`,
email: u.email,
memberSince: new Date(u.created).getFullYear(),
tier: u.subscriptions[0]?.tier || 'free'
})).sort((a, b) => a.name.localeCompare(b.name));
res.json(processed);
});Why it's wrong: The filter function contains complex business logic (subscription validation, verification checks) buried in an anonymous function. This logic can't be reused, tested independently, or understood without reading every line. Stack traces show anonymous functions if filtering logic fails.
✅ Compliant:
function hasActiveSubscription(user) {
return user.subscriptions?.some(subscription =>
subscription.status === 'active' &&
new Date(subscription.expiresAt) > new Date()
);
}
function isVerifiedUser(user) {
return user.emailVerified && user.phoneVerified && !user.deleted;
}
function isEligibleUser(user) {
return hasActiveSubscription(user) && isVerifiedUser(user);
}
function formatUserResponse(user) {
return {
id: user.id,
name: `${user.firstName} ${user.lastName}`,
email: user.email,
memberSince: new Date(user.created).getFullYear(),
tier: user.subscriptions[0]?.tier || 'free'
};
}
function sortByName(a, b) {
return a.name.localeCompare(b.name);
}
app.get('/users', async (req, res) => {
const users = await db.users.find({});
const processed = users
.filter(isEligibleUser)
.map(formatUserResponse)
.sort(sortByName);
res.json(processed);
});Why this matters: Complex business logic is extracted into testable functions. hasActiveSubscription() and isVerifiedUser() can be unit tested and reused. Stack traces show function names, making debugging faster. The endpoint logic is clean and self-documenting.
Conclusion
Use named functions for any logic longer than 2-3 lines or any logic that might be reused. Reserve anonymous functions for trivial operations where the function name would be longer than the implementation. Descriptive function names serve as inline documentation.
.avif)
