# Cheat Sheet: JavaScript (TypeScript) variable naming convention

*Recommendations on how to unify naming convention within a code – formats, acronyms and abbreviations, value-based prefixes, event handlers, etc. Mainly for vanilla TypeScript with a bit of React.*

## Variable name formats

It is good to restrict name formats to those listed below unless there is an extraordinary reason (e.g. pairing with database column names):

* `camelCase` – default name format,
    
* `PascalCase` – format of classes, types, enum-like structures, interfaces and special structures (e.g. React component names),
    
* `SCREAMING_SNAKE_CASE` – global constants.
    

We can use full words (`properties`), abbreviations (`props`) and acronyms within variable names.

* 2 letter acronyms are uppercase.
    
* 3+ letter acronyms are lowercase.
    

```typescript
// 2 letters
const TranslationsEn = {};  // abbreviation
const enTranslations = {};  // abbreviation
const adminUI = {};         // acronym
const adminUIAdvanced = {}; // acronym
const UIButton = {};        // acronym

// 3+ letters
type ComponentProps = {};  // abbreviation
const htmlTags = [];       // acronym
const copyHtml = () => {}; // acronym
```

## Custom values

All variables must be named to reflect the meaning of the stored value. The name format is chosen according to the list above. In special cases (boolean values, enums, etc.), variable names may use a unique prefix or rule to distinguish themselves from the rest.

```typescript
// <variableDescription>
const result = 1;
const nextMiddleware = "logger";

// <VARIABLE_DESCRIPTION>
const ENVIRONMENT_VARIABLE = process.env.ENVIRONMENT_VARIABLE;
```

## Boolean values - is, are, has

These variables should only contain `true`/`false` boolean (not `string`) values and thus implicitly declare that they are safe to use in conditions.

```typescript
// (is|are)[<Noun>]<Adjective>
const isSubmitted = false;
const isFormASubmitted = false;
const isFormBSubmitted = false;
const areFormsSubmitted = isFormASubmitted && isFormBSubmitted;

// (is|are)<Action>
const isFetching = true;

// has<SubjectDescription>
const hasAtLeastOneOddNumber = true;

// Global constant with IS prefix
const IS_DEBUG_MODE = true;
```

Prefixes `is`/`are` have a priority over `has` – don't name a variable `hasDefinedStatus` when you can use `isStatusDefined`. The prefix `has` should be used in cases that cannot be comfortably replaced with `is`/`are`, e.g. `hasTwoElementsFromArray`.

**Negation**

Sometimes, negation is used as frequently as the original value, or we need to operate with negative statements only. In these cases, we can use a secondary `Not` prefix.

```typescript
const isFormatted = false;
const isNotFormatted = !isFormatted;
```

## Enums

Enums have a special behaviour - TypeScript `enum` as a type is not the best concept, according to the [TypeScript Team](https://www.youtube.com/watch?v=vBJF0cJ_3G0&t=1012s). Therefore it is better to use an object with `as const` structure ([explanation](https://www.youtube.com/watch?v=0fTdCSH_QEU&t=294s)). According to [Google JS Guide](https://google.github.io/styleguide/jsguide.html#features-objects-enums), we can think of this object as a special structure (`PascalCase`) containing constants (`SCREAMING_SNAKE_CASE`).

```typescript
const RequestStatus = {
   PENDING: 'Pending',
   SUCCESS: 'Success',
   ERROR: 'Error',
} as const;

type RequestStatus = (typeof RequestStatus)[keyof typeof RequestStatus];

// Usage
RequestStatus.SUCCESS;
```

## Types, interfaces and generics

Types use `PascalCase` and do not need a special prefix. Interfaces and generics have one letter prefix because of their special use cases (useful mainly in libraries).

```typescript
// <TypeName>
type SystemProps = {};

// I<InterfaceName>
interface ISystemProps {}

// T<GenericType>
const createValue = <TInputValue>(value: TInputValue) => {
   return value;
};
```

## Event handlers

Event handlers (callbacks) are functions that are called after an event – e.g. HTML `onclick`, `oncontextmenu`, React events, etc.

```typescript
// handle[<Object>]<Action>
const handleClick = () => {};           // click is clearly defined
const handleSendButtonClick = () => {}; // one of many click events
const handleSignOut = () => {}          // multi-usage close callback
```

* `Object` - defines unique items that we interact with. It is optional if the handler is called from multiple places or if it is unique within the code part.
    
* `Action` - an action caused by a user.
    

**React** applications are a special case using `onX={handleX}` pairs.

```typescript
type ComponentProps = {
   onSignInFormSubmit: () => {};
};

const Component = ({ onSignInFormSubmit }: ComponentProps) => {};

const Parent = () => {
   const handleSignInFormSubmit = () => {};
   return <Component onSignInFormSubmit={handleSignInFormSubmit} />
}
```

It is better to not name handlers with `on` prefix unless you, for example, want to create an auto-spreading structure of build-in properties (using spread syntax with prop names `onClick`, etc.). Detailed explanation: [Event Handler Naming in React (by Jake Trent)](https://jaketrent.com/post/naming-event-handlers-react/).

## Functions

A function is always some kind of action. Therefore, its name should begin with a verb. It is a good idea to fix a set of these verbs and describe their purpose.

```typescript
// transform[Entity]to[Entity]
const transformResultToOrderedArray = () => {}

// format[Entity]As[Entity]
const formatTimestampAsLocalizedEnString = () => {}

// (generate|gen)[Entity]
const generateRandomTraceId = () => {}
const genRandomTraceId = () => {}
```

HTTP method functions (return a result of fetch API) should be named with a method that they return:

```typescript
// <method><Entity>
const getArticles = () => {};
const postArticle = () => {};
const putArticle = () => {};
const patchArticle = () => {};
const deleteArticle = () => {};
// ...
```

## Class private attributes and methods

According to [Private Fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties) we need to use `#` (hash names) for private methods and attributes.

```javascript

class PrivateNumber {
	#x;

	constructor(x) {
		this.#x = x;
	}

	get #privateSecretValue() {
		return this.#x + 10;
	}

	get secretValue() {
		return this.#privateSecretValue;
	}
}
```

## Conclusion

After all, it is not so important which style, rules or prefixes we use. They just need to be consistent at least within a project. But we make our (and our colleagues) lives easier when we use at least somehow unified conventions.
