Skip to main content

Naming conventions 1: case conventions, variables, and constants

This topic comes in three parts

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).

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

kebab-case cannot be used for TypeScript variable names (because 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​

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',
}
Answer and explanation
✅ 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 tells you what is the case when the value is true.

Prefix 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);
Answer and explanation
✅ 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"];
Answer and explanation
✅ 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"];