This guide prevents the variable naming issues that caused runtime errors like "options is not defined", "error is not defined", etc.
We discovered a systematic issue where parameters were prefixed with underscores (_error, _options, _params) but referenced in function bodies without the underscore (error, options, params). This caused runtime "variable is not defined" errors.
// ❌ WRONG: Parameter has underscore, but body references without underscore
function example(_options: Options) {
if (options.debug) {
// Error: options is not defined
console.log("Debug mode");
}
}
// ❌ WRONG: Catch parameter has underscore, but body references without underscore
try {
doSomething();
} catch (_error) {
console.log(error.message); // Error: error is not defined
}Use underscores ONLY for truly unused parameters:
// ✅ CORRECT: Unused parameter with underscore
function handler(_unusedEvent: Event, data: Data) {
return processData(data);
}
// ✅ CORRECT: Used parameter without underscore
function handler(event: Event, data: Data) {
console.log(event.type);
return processData(data);
}For catch blocks:
// ✅ CORRECT: Used error without underscore
try {
doSomething();
} catch (error) {
console.log(error.message);
}
// ✅ CORRECT: Unused error with underscore (rare)
try {
doSomething();
} catch (_error) {
// Error is intentionally ignored
return defaultValue;
}// ✅ CORRECT: All parameters used, no underscores
function processTask(taskId: string, options: Options) {
const task = getTask(taskId);
if (options.validate) {
validateTask(task);
}
return task;
}
// ✅ CORRECT: Mixed used/unused parameters
function processTask(taskId: string, _metadata: Metadata, options: Options) {
const task = getTask(taskId);
// _metadata is intentionally unused
if (options.validate) {
validateTask(task);
}
return task;
}Run this to find issues:
bun run scripts/check-variable-naming.tsRun this to fix many issues automatically:
bun run scripts/fix-variable-naming.tsOur .eslintrc.json includes rules to prevent these issues:
@typescript-eslint/no-unused-varswith underscore patterns@typescript-eslint/naming-conventionto forbid leading underscores on used variables
The pre-commit hook automatically checks for these issues before allowing commits.
-
Truly unused parameters (especially in interfaces/callbacks):
interface EventHandler { onEvent(_event: Event, data: Data): void; }
-
Destructuring with unused values:
const [first, _second, third] = array;
-
Function signatures that must match an interface but don't use all parameters:
// Interface requires both parameters const handler: EventHandler = (_event, data) => { return processData(data); };
For existing code with these issues:
- Run the checker to identify all issues
- Use the fixer script to automatically resolve most cases
- Manual review for complex cases
- Test thoroughly after changes
- Commit incrementally to track changes
// Before: catch (_error) { ... error ... }
// After: catch (error) { ... error ... }// Before: function fn(_param) { ... param ... }
// After: function fn(param) { ... param ... }// Before: (_arg) => { ... arg ... }
// After: (arg) => { ... arg ... }The systematic fix resolved this error progression:
- "options is not defined" → Fixed workspace.ts
- "error is not defined" → Fixed catch blocks
- "params is not defined" → Fixed parameter names
- "tasks is not defined" → Fixed variable declarations
- SUCCESS → CLI commands work correctly
After applying fixes, verify with:
# Check for remaining issues
bun run scripts/check-variable-naming.ts
# Test the CLI commands that were failing
minsky tasks list
minsky tasks status set 049
# Run the full test suite
bun testThis naming convention is now enforced by:
- ESLint custom rule
no-underscore-prefix-mismatchineslint-rules/no-underscore-prefix-mismatch.js - Pre-commit hooks in
.husky/pre-commit - Automated scripts in
scripts/
Following these guidelines prevents runtime "variable is not defined" errors and ensures consistent, maintainable code.