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.
// 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.
// <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.
// (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.
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. Therefore it is better to use an object with as const
structure (explanation). According to Google JS Guide, we can think of this object as a special structure (PascalCase
) containing constants (SCREAMING_SNAKE_CASE
).
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).
// <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.
// 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.
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).
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.
// 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:
// <method><Entity>
const getArticles = () => {};
const postArticle = () => {};
const putArticle = () => {};
const patchArticle = () => {};
const deleteArticle = () => {};
// ...
Class private attributes and methods
According to Private Fields we need to use #
(hash names) for private methods and attributes.
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.