Skip to main content

Naming conventions 1: case conventions, variables, and constants

This topic comes in three parts

Naming conventions are split across three articles. This article (Part 1) covers case conventions and naming variables, booleans, and constants. It continues with Part 2: Functions and Classes and Part 3: Improving naming quality.

Why variable names matter

Good variable names make it possible for the code itself to become documentation.

❌ Bad: The intent is not conveyed

❌ Bad: The intent is not conveyed
const a = 300 / 60;

Problems:

  • It is unclear what a represents
  • The meaning of 300 and 60 is unclear
  • It cannot be understood without a comment

✅ Good: The intent is clear

✅ Good: The intent is clear
const minutes = 300;
const hours = minutes / 60;

Improvements:

  • The variable names make the intent "convert minutes to hours" clear
  • The units of the numbers can be understood
  • It is self-explanatory and needs no comment

When the naming changes, the meaning of the code changes


Identifiers and case

There are mainly four patterns of naming conventions for identifiers (variable names, function names, class names, and so on).

Types of naming conventions

TypeExample
kebab-casekebab-case, user-name
snake_casesnake_case, user_name
PascalCasePascalCase, UserData
camelCasecamelCase, userName

1. kebab-case

Description: Connect words with hyphens (-).

✅ Good: Use cases: HTML attributes, URLs, CSS class names
// ✅ Use cases: HTML attributes, URLs, CSS class names
<!-- HTML attribute -->
<input name="user-name" />
<section class="content-width">...</section>

<!-- URL -->
https://example.com/sales-profit
https://example.com/user-profile

Do not use it for TypeScript variables (a hyphen is interpreted as the subtraction operator)

❌ Bad: Error!
// ❌ Error!
const user-name = "Taro"; // SyntaxError

2. snake_case

Description: Connect words with underscores (_).

✅ Good: Use cases (limited in TypeScript)
// ✅ Use cases (limited in TypeScript)

camelCase is generally recommended in TypeScript, but snake_case is sometimes used in the following cases:

// When matching database column names
interface UserRecord {
user_id: number;
first_name: string;
last_name: string;
created_at: Date;
}

// When matching an external API's response
type ApiResponse = {
access_token: string;
refresh_token: string;
expires_in: number;
};

UPPER_SNAKE_CASE

Description: All uppercase, connected with underscores.

✅ Good: Use case: constants (values that don't change)
// ✅ Use case: constants (values that don't change)
const MAX_USER_COUNT = 100;
const API_BASE_URL = "https://api.example.com";
const DEFAULT_TIMEOUT_MS = 5000;

// ✅ Enum values
const ORDER_TYPE = {
NEW_ENTRY: 0,
UPDATE_PLAN: 10,
CANCEL_CONTRACT: 30,
} as const;

3. PascalCase

Description: Capitalize the first letter of every word (also called upper camel case).

✅ Good: Use cases: classes, interfaces, type aliases, enums
// ✅ Use cases: classes, interfaces, type aliases, enums

// Class
class UserAccount {
private userName: string;

constructor(userName: string) {
this.userName = userName;
}
}

// Interface
interface UserProfile {
id: number;
name: string;
email: string;
}

// Type alias
type ApiResult<T> = {
data: T;
status: number;
};

// Enum
enum OrderStatus {
Pending,
Processing,
Completed,
Cancelled,
}

// React component (function component)
function UserProfileCard({ user }: { user: UserProfile }) {
return <div>{user.name}</div>;
}

4. camelCase

Description: Lowercase the first word, then capitalize the first letter of each following word.

✅ Good: Use cases: variables, functions, methods, properties
// ✅ Use cases: variables, functions, methods, properties

// Variables
const userName = "Taro";
const totalAmount = 1000;
const isAuthenticated = true;

// Function
function calculateTotalPrice(price: number, quantity: number): number {
return price * quantity;
}

// Method
class ShoppingCart {
private items: Item[] = [];

addItem(item: Item): void {
this.items.push(item);
}

getTotalPrice(): number {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
}

// Object properties
const userSettings = {
displayName: "Taro Yamada",
emailAddress: "taro@example.com",
notificationEnabled: true,
};

A summary of naming conventions in TypeScript

// ────────────────────────────────────────────
// 📋 TypeScript naming conventions cheat sheet
// ────────────────────────────────────────────

// 1️⃣ Variables and constants
const userName = "Taro"; // ✅ camelCase (regular variable)
const MAX_RETRY_COUNT = 3; // ✅ UPPER_SNAKE_CASE (constant)

// 2️⃣ Functions
function getUserById(id: number) {} // ✅ camelCase

// 3️⃣ Classes
class UserAccount {} // ✅ PascalCase

// 4️⃣ Interfaces
interface UserProfile {} // ✅ PascalCase
// Don't add an "I" prefix to interfaces (not recommended)
interface IUserProfile {} // ❌ An old convention

// 5️⃣ Type aliases
type UserId = string; // ✅ PascalCase
type UserData = { id: number }; // ✅ PascalCase

// 6️⃣ Enums
enum UserRole { // ✅ PascalCase (type name)
Admin, // ✅ PascalCase (member)
User,
Guest,
}

// 7️⃣ Generic type parameters
function identity<T>(value: T): T { return value; } // ✅ A single uppercase letter (T, U, V, and so on)
class Container<TItem> {} // ✅ Or T + a descriptive name

// 8️⃣ Private fields
class User {
private userName = ""; // ✅ camelCase
#password = ""; // ✅ # prefix (ECMAScript private)
}

Exercise 1: Applying naming conventions

Let's rewrite the following code with the correct naming conventions.

❌ Bad: Before
// ❌ Before
class user_data {
constructor(public user_name: string) {}
}

interface product_info {
product_id: number;
product_name: string;
}

const TAX_RATE = 0.1;
function CALCULATE_PRICE(price: number): number {
return price * (1 + TAX_RATE);
}

enum order_status {
pending = 'PENDING',
completed = 'COMPLETED',
}
📝 View answer
✅ Good: After
// ✅ After

// Classes use PascalCase
class UserData {
constructor(public userName: string) {}
}

// Interfaces use PascalCase, properties use camelCase
interface ProductInfo {
productId: number;
productName: string;
}

// Constants use UPPER_SNAKE_CASE
const TAX_RATE = 0.1;

// Functions use camelCase
function calculatePrice(price: number): number {
return price * (1 + TAX_RATE);
}

// Enums use PascalCase
enum OrderStatus {
Pending = 'PENDING',
Completed = 'COMPLETED',
}

※ This exercise covers only case conversion (uppercase/lowercase and how words are separated). For whether the name UserData itself is good, see the "Avoid meaningless words" section in Part 3.


Naming conventions for variables

Principle: a variable clearly expresses "what it stores"

❌ Bad: Too abstract
// ❌ Bad: Too abstract
let number = 20;
let str = "red";
let data = { id: 1 };

// ✅ Good: Concrete and clear in meaning
let age = 20;
let themeColor = "red";
let userData = { id: 1 };

Don't include type information in variable names

Because TypeScript has a type system, you don't need to include type information in variable names.

❌ Bad: Including type information in the name (Hungarian notation)
// ❌ Bad: Including type information in the name (Hungarian notation)
const strUserName = "Taro";
const numAge = 25;
const arrItems: number[] = [1, 2, 3];
const objUser = { id: 1 };

// ✅ Good: Express the type with a type annotation
const userName: string = "Taro";
const age: number = 25;
const items: number[] = [1, 2, 3];
const user: User = { id: 1 };

// ✅ Better: Leverage type inference (avoid redundant type annotations)
const userName = "Taro"; // Inferred as string
const age = 25; // Inferred as number
const items = [1, 2, 3]; // Inferred as number[]
const user: User = { id: 1 }; // Only when the type must be explicit

Naming conventions for booleans

Name a variable that holds a boolean so the name expresses whether the value is true or false.

Prefix patterns

Boolean naming patterns

PatternExample
is + noun / adjectiveisVisible, isValid
has + nounhasError, hasChildren
can + verbcanEdit, canDelete
should + verbshouldUpdate, shouldRetry
past participlecompleted, finished

Concrete examples

✅ Good: is + adjective/noun
// ✅ is + adjective/noun
const isVisible = true;
const isAuthenticated = false;
const isValid = checkValidity();
const isLoading = true;
const isEmpty = array.length === 0;

// ✅ has + noun
const hasError = errors.length > 0;
const hasChildren = node.children.length > 0;
const hasPermission = user.role === 'admin';

// ✅ can + verb
const canEdit = user.permissions.includes('edit');
const canDelete = user.role === 'admin';
const canSubmit = isValid && !isLoading;

// ✅ should + verb
const shouldUpdate = newVersion > currentVersion;
const shouldRetry = attemptCount < MAX_RETRIES;
const shouldShowWarning = diskUsage > 0.9;

// ✅ Past participle
const completed = tasks.every(task => task.status === 'done');
const enabled = settings.featureFlags.newUI;

❌ Patterns to avoid

❌ Bad: Patterns to avoid
// ❌ Bad: Avoid negative forms (double negatives cause confusion)
const notComplete = false;
if (!notComplete) { // Hard to read
// ...
}

// ✅ Good: Use the positive form
const isComplete = true;
if (isComplete) { // Easy to read
// ...
}

// ❌ Bad: Avoid expressing a boolean with a verb alone
const display = true; // "display" is a verb, so it's easily confused with a function

// ✅ Good: is + past participle
const isDisplayed = true;

// ❌ Bad: Using a type name
const boolean = true;
const string = typeof value === 'string';

// ✅ Good: Express the concrete state
const isEnabled = true;
const isString = typeof value === 'string';

Exercise 2: Naming booleans

// Fix the following variable names with appropriate naming

// 1. Whether the user is an adult
const xxx = age >= 18;

// 2. Whether the array is empty
const xxx = array.length === 0;

// 3. Whether the user has edit permission
const xxx = user.role === 'admin' || user.role === 'editor';

// 4. Whether the file exists
const xxx = fs.existsSync(filePath);

// 5. Whether all tasks are completed
const xxx = tasks.every(task => task.done);
📝 View answer
✅ Good: Answer
// ✅ Answer

// 1. Whether the user is an adult
const isAdult = age >= 18;
// or
const isOfAge = age >= 18;

// 2. Whether the array is empty
const isEmpty = array.length === 0;

// 3. Whether the user has edit permission
const canEdit = user.role === 'admin' || user.role === 'editor';
// or
const hasEditPermission = user.role === 'admin' || user.role === 'editor';

// 4. Whether the file exists
const fileExists = fs.existsSync(filePath);
// or
const hasFile = fs.existsSync(filePath);

// 5. Whether all tasks are completed
const allCompleted = tasks.every(task => task.done);
// or
const isAllTasksCompleted = tasks.every(task => task.done);

Naming conventions for constants

What is a constant

In TypeScript, "constant" has two meanings:

  1. A variable that cannot be reassigned (declared with const)
  2. A value that is immutable across the whole application (configuration values, replacements for magic numbers, and so on)
// ────────────────────────────────────────────
// Understand the two meanings of const
// ────────────────────────────────────────────

// 1️⃣ A variable that cannot be reassigned (a regular const)
const user = { name: "Taro" };
user.name = "Hanako"; // ✅ Changing a property is allowed
// user = {}; // ❌ Reassignment is not allowed

// 2️⃣ A completely immutable value (an application constant)
const MAX_RETRY_COUNT = 3; // ✅ UPPER_SNAKE_CASE
const API_BASE_URL = "https://api.example.com";

Choosing between conventions

✅ Good: environment variables, configuration values
// ────────────────────────────────────────────
// UPPER_SNAKE_CASE
// ────────────────────────────────────────────
// Use: values that don't change across the whole application

// ✅ Environment variables, configuration values
const API_ENDPOINT = "https://api.example.com";
const DEFAULT_LOCALE = "ja-JP";
const MAX_FILE_SIZE_MB = 10;

// ✅ Replacements for magic numbers
const TAX_RATE = 0.1;
const SECONDS_PER_MINUTE = 60;
const MILLISECONDS_PER_SECOND = 1000;

// ✅ Loop upper bounds
const MAX_RETRY_ATTEMPTS = 3;
const PAGE_SIZE = 20;

// ✅ Constant objects (using as const)
const HTTP_STATUS = {
OK: 200,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
NOT_FOUND: 404,
} as const;

const ORDER_TYPE = {
NEW_ENTRY: 0,
UPDATE_PLAN: 10,
CANCEL_CONTRACT: 30,
} as const;

// ────────────────────────────────────────────
// camelCase
// ────────────────────────────────────────────
// Use: regular variables (objects, arrays, and so on)

// ✅ Object instances
const userSettings = {
theme: "dark",
language: "ja",
};

// ✅ Arrays
const itemList = [1, 2, 3];

// ✅ Class instances
const httpClient = new HttpClient();

// ✅ Function results
const calculatedValue = calculateTotal();

Making types strict with as const

Using as const makes a value completely immutable and lets the type be treated as a literal type.

❌ Bad: without as const
// ────────────────────────────────────────────
// The effect of as const
// ────────────────────────────────────────────

// ❌ Without as const
const ORDER_TYPE_1 = {
NEW: 0,
UPDATE: 10,
};
// Type: { NEW: number; UPDATE: number }
// The type of ORDER_TYPE_1.NEW is number (too wide)

// ✅ With as const
const ORDER_TYPE_2 = {
NEW: 0,
UPDATE: 10,
} as const;
// Type: { readonly NEW: 0; readonly UPDATE: 10 }
// The type of ORDER_TYPE_2.NEW is 0 (strict, a literal type)

// ✅ Practical example: a type-safe constant object
const USER_ROLE = {
ADMIN: 'admin',
USER: 'user',
GUEST: 'guest',
} as const;

// Extract the type
type UserRole = typeof USER_ROLE[keyof typeof USER_ROLE];
// Type: "admin" | "user" | "guest"

function checkPermission(role: UserRole) {
if (role === USER_ROLE.ADMIN) {
// ...
}
}

checkPermission(USER_ROLE.ADMIN); // ✅ OK
checkPermission('admin'); // ✅ OK
// checkPermission('superuser'); // ❌ Error

Exercise 3: Naming constants

// Name the following constants appropriately

// 1. Consumption tax rate (10%)
const xxx = 0.1;

// 2. Maximum number of login attempts
const xxx = 5;

// 3. User information (object)
const xxx = {
id: 1,
name: "Taro"
};

// 4. List of error codes
const xxx = {
notFound: 404,
serverError: 500,
};

// 5. Array of days of the week
const xxx = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
📝 View answer
✅ Good: Answer
// ✅ Answer

// 1. Consumption tax rate (10%) - a value that doesn't change, so UPPER_SNAKE_CASE
const TAX_RATE = 0.1;

// 2. Maximum number of login attempts - a configuration value, so UPPER_SNAKE_CASE
const MAX_LOGIN_ATTEMPTS = 5;

// 3. User information (object) - an instance, so camelCase
const currentUser = {
id: 1,
name: "Taro"
};

// 4. List of error codes - a constant object, so UPPER_SNAKE_CASE + as const
const ERROR_CODE = {
NOT_FOUND: 404,
SERVER_ERROR: 500,
} as const;

// 5. Array of days of the week - an unchanging list, so either could apply
const DAYS_OF_WEEK = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] as const;
// or, depending on the use
const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];