Skip to content

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 (all types including const global), function, parameter, memberLike (class members)
Applied: Lowest precedence (catch-all safety net)

TIP

Abbreviation restrictions apply to all identifiers, including:

  • Local variables
  • Global const variables (module-level constants)
  • Function parameters
  • Function names
  • Class members (public, private, protected, static, readonly)

Why This Rule

Single-letter names and ambiguous abbreviations are among the most common sources of confusion in codebases:

  • Single-letter variables → Banned except for coordinates (x, y, z)
    • i/j/k → Use index, rowIndex, colIndex instead
    • e → Use error, event, or element depending on context
    • s → Use string, source, or status depending on context
    • n → Use count, length, or number depending on context
    • Only exception: x, y, z are allowed for coordinate systems and geometry
  • Ambiguous abbreviations → Use full descriptive names
    • data/info/obj → What kind of data? Use responseBody, metadata, userPayload, payload
    • res/req → Acceptable in Express handlers, but ambiguous elsewhere (result? resource? response?)
    • err → Use error - it's only 2 more characters
    • data → Too vague - use specific terms like payload, result, records, responseBody, input, output

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:

typescript
{
  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:

typescript
['id', 'url', 'api', 'ui', 'db', 'json', 'html', 'uuid', 'jwt', 'ip', 'http', ...]

✅ Good

ts
// Valid names that avoid abbreviations from the DENY_LIST

function abbreviationsPositiveExample() {
  // Variables - full descriptive names
  const userData = { id: 1, name: 'Alice' }; // ✅ id is in ALLOW_LIST
  const apiUrl = 'https://example.com'; // ✅ api, url in ALLOW_LIST
  const userCount = 10; // ✅ not abbreviated
  const responseBody = { status: 'ok' }; // ✅ instead of "res"
  const errorMessage = 'Failed'; // ✅ instead of "err"
  const callback = () => {}; // ✅ instead of "cb"
  const element = document.createElement('div'); // ✅ instead of "el"
  const button = document.createElement('button'); // ✅ instead of "btn"
  const directory = '/home/user'; // ✅ instead of "dir"
  const filePath = '/home/user/file.txt'; // ✅ instead of "fpath"
  const configuration = { debug: true }; // ✅ instead of "cfg"
  const timestamp = Date.now(); // ✅ instead of "ts"
  const message = 'Hello'; // ✅ instead of "msg"
  const minimum = 0; // ✅ instead of "min"
  const maximum = 100; // ✅ instead of "max"
  const index = 0; // ✅ instead of "i", "j", "k", or "idx"
  const itemIndex = 1; // ✅ instead of "i"
  const rowIndex = 2; // ✅ instead of "j"

  // Single-letter coordinates are allowed (x, y, z)
  const x = 10; // ✅ allowed for coordinates
  const y = 20; // ✅ allowed for coordinates
  const z = 30; // ✅ allowed for 3D coordinates

  return {
    userData,
    apiUrl,
    userCount,
    responseBody,
    errorMessage,
    callback,
    element,
    button,
    directory,
    filePath,
    configuration,
    timestamp,
    message,
    minimum,
    maximum,
    index,
    itemIndex,
    rowIndex,
    x,
    y,
    z,
  };
}

// Functions - descriptive names
function processUserData() {} // ✅
function handleErrorMessage() {} // ✅
function formatTimestamp() {} // ✅
function validateDirectory() {} // ✅

// Parameters - descriptive names
function processRequest(requestData: unknown, onComplete: () => void) {
  // ✅
  return { requestData, onComplete };
}

function handleResponse(responseData: unknown, metadata: unknown) {
  // ✅
  return { responseData, metadata };
}

❌ Bad

ts
// Invalid names that use banned abbreviations from DENY_LIST

// Global variables - banned abbreviations
export const msg = 'Hello'; // ❌ should be: message
const cfg = {}; // ❌ should be: config or configuration

function abbreviationsNegativeExample() {
  // Single-letter variables (except x, y, z) - all banned
  const a = [1, 2, 3]; // ❌ should be: array, items, values, etc.
  const b = true; // ❌ should be: boolean, isEnabled, flag, etc.
  const c = 'character'; // ❌ should be: character, count, class, etc.
  const d = { key: 'value' }; // ❌ should be: data, payload, etc.
  const e = new Error(); // ❌ should be: error, exception, event
  const f = () => {}; // ❌ should be: function, callback, handler
  const i = 0; // ❌ should be: index, itemIndex, rowIndex
  const j = 1; // ❌ should be: index, itemIndex, rowIndex
  const k = 2; // ❌ should be: index, key, keyIndex
  const n = 10; // ❌ should be: count, number, length
  const p = { x: 0, y: 0 }; // ❌ should be: point, position, parameter
  const s = 'text'; // ❌ should be: string, text, value
  const t = Date.now(); // ❌ should be: time, timestamp, token

  // Variables - banned abbreviations
  const str = 'text'; // ❌ should be: string or text
  const num = 42; // ❌ should be: number or count
  const arr = [1, 2, 3]; // ❌ should be: array or items
  const obj = { key: 'value' }; // ❌ should be: object or specific domain name
  const fn = () => {}; // ❌ should be: function or callback
  const cb = () => {}; // ❌ should be: callback or onComplete
  const err = new Error(); // ❌ should be: error
  const tmp = 'temp'; // ❌ should be: temporary or tempValue
  // NOTE: 'data', 'min', 'max' are in ALLOW_LIST, so they are not tested here
  const info = {}; // ❌ should be: metadata or details
  const val = 42; // ❌ should be: value
  const idx = 0; // ❌ should be: index
  const cnt = 5; // ❌ should be: count
  const len = 10; // ❌ should be: length
  const dir = '/path'; // ❌ should be: directory or direction
  const btn = null; // ❌ should be: button
  const el = null; // ❌ should be: element
  const img = null; // ❌ should be: image

  return {
    a,
    b,
    c,
    d,
    e,
    f,
    i,
    j,
    k,
    n,
    p,
    s,
    t,
    str,
    num,
    arr,
    obj,
    fn,
    cb,
    err,
    tmp,
    info,
    val,
    idx,
    cnt,
    len,
    dir,
    btn,
    el,
    img,
  };
}

// Functions - banned abbreviations
function processStr() {} // ❌ should be: processString
function handleErr() {} // ❌ should be: handleError
function formatMsg() {} // ❌ should be: formatMessage
function validateCfg() {} // ❌ should be: validateConfig

// Parameters - banned abbreviations
function processReq(req: unknown, res: unknown) {
  // ❌ req and res should be: request and response (unless in framework context)
  return { req, res };
}

function handleData(data: unknown, info: unknown) {
  // ❌ data should be more specific: payload, result, records, etc.
  // ❌ info should be more specific: metadata, details, etc.
  return { data, info };
}

Customization

You can customize the lists for your project:

typescript
// 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:

typescript
// 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

Single-letter loop variables like i, j, k are banned. Use descriptive names instead:

typescript
// ❌ Bad - single-letter loop variables
for (let i = 0; i < items.length; i++) {
  console.log(items[i]);
}

// ✅ Better - use array iteration methods
for (const item of items) {
  console.log(item);
}

// ✅ Good - descriptive name when index is needed
items.forEach((item, itemIndex) => {
  console.log(itemIndex, item);
});

// ✅ Good - descriptive names in traditional loops
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:

typescript
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

ts
/**
 * 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 (x, y, z are allowed for coordinates)
  a: ['array', 'attribute', 'value', 'accumulator'],
  b: ['boolean', 'buffer', 'byte', 'value'],
  c: ['character', 'count', 'class', 'component'],
  d: ['data', 'day', 'distance', 'delta'],
  e: ['event', 'error', 'exception', 'element'],
  f: ['function', 'field', 'flag', 'file'],
  g: ['group', 'global', 'get'],
  h: ['height', 'handler', 'hash', 'header'],
  i: ['index', 'itemIndex', 'rowIndex', 'columnIndex'],
  j: ['index', 'itemIndex', 'rowIndex', 'columnIndex'],
  k: ['index', 'key', 'keyIndex'],
  l: ['length', 'list', 'line', 'label'],
  m: ['map', 'message', 'method', 'model'],
  n: ['count', 'length', 'number', 'node'],
  o: ['object', 'option', 'output'],
  p: ['parameter', 'property', 'position', 'point'],
  q: ['query', 'queue', 'question'],
  r: ['result', 'response', 'record', 'row'],
  s: ['string', 'source', 'state', 'status'],
  t: ['type', 'time', 'token', 'text'],
  u: ['user', 'url', 'unit', 'update'],
  v: ['value', 'variable', 'version'],
  w: ['width', 'window', 'wrapper'],
  // x, y, z are allowed in ALLOW_LIST for coordinate systems

  // 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'],
  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

ts
/**
 * 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',
  'repo',

  // Node / platform conventions
  'fs', // Node.js "fs" module is standard

  // Framework-idiomatic params (consider allowing only as parameters)
  // 'req',
  // 'res',
  // 'ctx',
  'next',

  // Single-letter coordinate variables (allowed for geometry/render contexts)
  'x',
  'y',
  'z',
] as const;

For the complete DENY_LIST and ALLOW_LIST, see:

References