Abbreviation Restrictions
Automatically enforces descriptive naming by banning common abbreviations and anti-patterns.
Overview
This feature prevents usage of common abbreviations that reduce code readability. It's based on a comprehensive deny-list of anti-patterns, while allowing well-established technical terms and framework conventions through an allow-list.
Selector: variable, function, parameter
Applied: Lowest precedence (catch-all safety net)
Why This Rule
Single-letter names and ambiguous abbreviations are among the most common sources of confusion in codebases:
i/j/k→ What are you iterating over? Useindex,rowIndex,colIndexdata/info/obj→ What kind of data? UseresponseBody,metadata,userPayloadres/req→ Acceptable in Express handlers, but ambiguous elsewhere (result? resource? response?)err→ Useerror- it's only 2 more characters
Philosophy
This rule embodies the principle: "Write code for humans first, computers second."
Clear names:
- Reduce onboarding time for new team members
- Make code self-documenting
- Prevent bugs from misunderstanding
- Eliminate the need for guessing in code reviews
How It Works
The rule uses two lists:
DENY_LIST
Contains ~140+ common abbreviations and their recommended replacements:
{
str: ['string', 'text'],
num: ['number', 'amount', 'count'],
arr: ['array', 'list', 'items'],
obj: ['object', 'entity', 'payload'],
data: ['payload', 'result', 'records', 'responseBody'],
// ... and many more
}ALLOW_LIST
Contains widely-recognized technical terms that are acceptable:
['id', 'url', 'api', 'ui', 'db', 'json', 'html', 'uuid', 'jwt', 'ip', 'http', ...]✅ Good
// Variables - descriptive names
const userData = { id: 1, name: 'Alice' };
const responseBody = { status: 'ok' };
const errorMessage = 'Failed to connect';
const callback = () => {};
const element = document.querySelector('.button');
const directory = '/home/user';
const configuration = { debug: true };
const timestamp = Date.now();
const itemIndex = 0;
// Functions - clear intent
function processUserData() {}
function handleErrorMessage() {}
function formatTimestamp() {}
function validateDirectory() {}
// Parameters - no guessing needed
function handleRequest(requestData: Request, onComplete: () => void) {
// ...
}
function processResponse(responseData: Response, metadata: Metadata) {
// ...
}❌ Bad
// Variables - banned abbreviations
const str = 'text'; // ❌ Use: string or text
const num = 42; // ❌ Use: number or count
const arr = [1, 2, 3]; // ❌ Use: array or items
const obj = {}; // ❌ Use: object or specific domain name (user, config, etc.)
const data = {}; // ❌ Use: payload, result, records, etc.
const info = {}; // ❌ Use: metadata, details, summary
const tmp = 'temp'; // ❌ Use: temporary or tempValue
const cfg = {}; // ❌ Use: config or configuration
const msg = 'Hello'; // ❌ Use: message
const err = new Error(); // ❌ Use: error
const idx = 0; // ❌ Use: index
const btn = null; // ❌ Use: button
const el = null; // ❌ Use: element
// Functions - unclear abbreviations
function processStr() {} // ❌ Use: processString
function handleErr() {} // ❌ Use: handleError
function formatMsg() {} // ❌ Use: formatMessage
// Parameters - ambiguous
function process(req: Request, res: Response) {
// ❌ Outside Express/framework context, use: request, response
// ❌ req/res are ambiguous: result? resource?
}Customization
You can customize the lists for your project:
// eslint.config.js
import { ALLOW_LIST, DENY_LIST } from 'eslint-config-naming';
// Add your own allowed abbreviations
const myAllowList = [...ALLOW_LIST, 'req', 'res', 'ctx'];
// Or remove some from deny list for your use case
const myDenyList = { ...DENY_LIST };
delete myDenyList.req;
delete myDenyList.res;
// Then build your own custom regex using these lists
const bannedNames = Object.keys(myDenyList)
.filter((name) => !myAllowList.includes(name))
.map((s) => s.replaceAll(/[.*+?^${}()|[\]\\]/g, '\\$&'))
.join('|');
// Use in your custom naming-convention rule
export default [
{
rules: {
'@typescript-eslint/naming-convention': [
'error',
// ... your other rules
{
selector: 'variable',
format: null,
custom: { regex: `^(${bannedNames})$`, match: false },
},
],
},
},
];Common Exceptions
Framework Parameters
In Express.js, Koa, or similar frameworks, req, res, ctx, next are idiomatic:
// Acceptable in framework context
app.get('/users', (req, res, next) => {
// This is the established convention
});By default, these are allowed when used as parameters due to rule precedence. If your project uses them heavily, consider adding them to your custom allow-list.
Loop Indices
For simple array iteration, consider using:
// Instead of: for (let i = 0; i < items.length; i++)
for (const item of items) {
// Clearer intent
}
// Or with index when needed
items.forEach((item, itemIndex) => {
console.log(itemIndex, item);
});
// Traditional loop with descriptive names
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
for (let colIndex = 0; colIndex < cols.length; colIndex++) {
// Clear which dimension each index represents
}
}Technical Initialisms
Well-known technical terms are allowed:
const userId = 123; // ✅ 'id' is in ALLOW_LIST
const apiUrl = 'https://api.example.com'; // ✅ 'api' and 'url' are allowed
const jsonData = JSON.parse(response); // ✅ 'json' is allowed
const jwtToken = auth.getToken(); // ✅ 'jwt' is allowed🚫 Deny List
/**
* DENY_LIST:
* key = abbreviation / anti-pattern identifier you want to forbid
* value = allowed replacements (full names or clearer alternatives)
*/
export const DENY_LIST: Readonly<Record<string, readonly string[]>> = {
// Single-letter / too short
i: ['index', 'itemIndex', 'rowIndex', 'columnIndex'],
j: ['index', 'itemIndex', 'rowIndex', 'columnIndex'],
k: ['index', 'key', 'keyIndex'],
n: ['count', 'length', 'number'],
e: ['event', 'error', 'exception'],
x: ['xCoordinate', 'xPosition'],
y: ['yCoordinate', 'yPosition'],
// Core types / primitives
str: ['string', 'text'],
num: ['number', 'amount', 'count'],
bool: ['boolean', 'isEnabled', 'hasValue'],
fn: ['function', 'handler', 'callback'],
cb: ['callback', 'onComplete', 'onSuccess', 'onError'],
// Generic “intent-hiding” names (common anti-patterns)
data: ['payload', 'result', 'records', 'responseBody', 'input', 'output'],
info: ['metadata', 'details', 'summary', 'diagnostics'],
obj: ['object', 'entity', 'model', 'payload'], // or ideally: rename to the real domain noun
val: ['value', 'result', 'item', 'entry'],
tmp: ['temporary', 'tempValue', 'scratch'],
temp: ['temporary', 'tempValue', 'scratch'],
misc: ['other', 'fallback', 'unknown'],
stuff: ['items', 'things', 'resources'],
// Collections / data structures
arr: ['array', 'list', 'items', 'elements'],
lst: ['list', 'items', 'values'],
coll: ['collection', 'items', 'elements'],
dict: ['dictionary', 'map'],
kv: ['keyValue', 'keyValuePair'],
idx: ['index', 'itemIndex'],
cnt: ['count', 'total', 'quantity'],
qty: ['quantity', 'count', 'amount'],
len: ['length'],
max: ['maximum', 'upperBound'],
min: ['minimum', 'lowerBound'],
// Strings / formats
fmt: ['format', 'formatter'],
tpl: ['template'],
tmpl: ['template'],
re: ['regex', 'pattern'],
regex: ['regularExpression', 'pattern'], // if you want to enforce full wording
md: ['markdown'],
csv: ['commaSeparatedValues'],
tsv: ['tabSeparatedValues'],
// Time
dt: ['dateTime', 'date'],
ts: ['timestamp'],
ms: ['milliseconds'],
sec: ['seconds'],
mins: ['minutes'],
hrs: ['hours'],
dur: ['duration'],
ttl: ['timeToLive', 'cacheTtl'],
eta: ['estimatedTimeOfArrival', 'estimatedDuration'],
// Filesystem / paths
dir: ['directory', 'direction'], // ambiguous by design — choose meaning
cwd: ['currentWorkingDirectory'],
fname: ['fileName'],
fpath: ['filePath'],
ext: ['extension', 'fileExtension'],
buf: ['buffer'],
cfg: ['config', 'configuration'],
conf: ['config', 'configuration'],
// Web / networking (common ambiguous ones)
req: ['request'],
res: ['response', 'result', 'resource'], // ambiguous outside frameworks
resp: ['response'],
hdr: ['header'],
hdrs: ['headers'],
qs: ['queryString'],
q: ['query', 'queue'], // too ambiguous
urlStr: ['url', 'urlString'],
uriStr: ['uri', 'uriString'],
// Auth/security ambiguous
auth: ['authentication', 'authorization'], // pick one
authn: ['authentication'],
authz: ['authorization'],
cred: ['credential'],
creds: ['credentials'],
tok: ['token'],
jwtStr: ['jwt', 'jwtToken'],
// Architecture / layers
svc: ['service'],
ctrl: ['controller'],
mgr: ['manager'],
repo: ['repository'],
util: ['utility', 'helpers'],
impl: ['implementation'],
// UI / DOM
el: ['element'],
elem: ['element'],
evt: ['event'],
btn: ['button'],
lbl: ['label'],
img: ['image'],
nav: ['navigation'],
dlg: ['dialog'],
notif: ['notification'],
// Business-ish (often seen, often unclear)
usr: ['user'],
acct: ['account'],
addr: ['address'],
amt: ['amount'],
bal: ['balance'],
inv: ['invoice', 'inventory'], // ambiguous
// Database-ish
dbConn: ['databaseConnection'],
txn: ['transaction'],
tx: ['transaction'],
tbl: ['table'],
col: ['column'],
rec: ['record'],
recs: ['records'],
ver: ['version'],
rev: ['revision'],
// Observability
dbg: ['debug', 'debugInfo'],
msg: ['message'],
err: ['error'], // if you want “error” only; remove if you want to allow err
} as const;✅ Allow List
/**
* ALLOW_LIST:
* Identifiers allowed “as-is” because they are widely-recognized initialisms,
* ecosystem conventions, or required by external APIs/frameworks.
*
* Recommendation: In your ESLint rule, allow some of these ONLY in specific contexts:
* - function params: req, res, ctx, next
* - well-known technical initialisms: id, url, api, ui, db, json, html, css, uuid, jwt
*/
export const ALLOW_LIST: readonly string[] = [
// Very common initialisms / ubiquitous
'id',
'ids',
'url',
'urls',
'uri',
'uris',
'api',
'ui',
'ux',
'db',
'sql',
'json',
'yaml',
'yml',
'html',
'css',
'uuid',
'jwt',
'ip',
'dns',
'http',
'https',
'min',
'max',
'md',
'csv',
'tsv',
'ts', // false positive for TypeScript files
'ms',
'regex',
'data',
// Node / platform conventions
'fs', // Node.js "fs" module is standard
// Framework-idiomatic params (consider allowing only as parameters)
// 'req',
// 'res',
// 'ctx',
'next',
// Common coordinate vars (consider allowing only in geometry/render contexts)
'x',
'y',
] as const;For the complete DENY_LIST and ALLOW_LIST, see:
- src/naming-abbreviations.ts in the repository