TypeScript / JavaScript Coding Standards
FOR AI AGENTS: This document provides coding standards and best practices for TypeScript/JavaScript development. Follow these conventions for all code contributions.
1. Naming
A variable, function, or class name should provide clear answers to fundamental questions. It ought to explain its purpose, functionality, and usage. If a name necessitates a comment to clarify its intent, then the name itself lacks clarity.
1.1 Use meaningful variable names
Bad
const pr = productList.map((p) => p.price);
Good
const priceList = productList.map((product) => product.price);
Parameter names should communicate intent clearly
Bad
const hasChildren = (c: HTMLElement) => c.children.length !== 0;
Good
const hasChildren = (element: HTMLElement) => element.children.length !== 0;
1.2 Use pronounceable variable names
Avoid using terms that you struggle to pronounce.
Bad
class Cust {
public cId: number;
public billingAddrId: number;
public shippingAddrId: number;
}
Good
class Customer {
public id: number;
public billingAddressId: number;
public shippingAddressId: number;
}
1.3 Use names that are context specific
Avoid redundant information. Don't repeat yourself (DRY).
Bad (in a project called user_management)
const userLogin = () => {...};
const userRegister = () => {...};
Good
const login = () => {...};
const register = () => {...};
Using suffixes for clarity
Bad (in a project called acme)
const AcmeText = () => {};
Good
const Text = () => {};
Bad (in a class called Account)
type Account = {
accountId: string;
accountName: string;
accountType: string;
};
function print(account: Account) {
console.log(
`${account.accountId} ${account.accountType} (${account.accountName})`,
);
}
Good
interface Account {
id: string;
name: string;
type: string;
}
function print(account: Account) {
console.log(`${account.id} ${account.type} (${account.name})`);
}
1.4 Naming convention
- camelCase: variables and functions.
- UPPERCASE: constants.
- PascalCase: classes, interfaces, types, and enums.
Bad
const TotalPrice = 3.0 * tax;
function PrintAccountBalance() {...}
const NotifyUser = () => {};
Good
const totalPrice = 3.0 * tax;
function printAccountBalance() {...}
const notifyUser = () => {};
Booleans: Don't use negative names
Bad
const isNotLoading = true;
const isNotEnabled = true;
const isNotEqual = (a, b) => a !== b;
Good
const isLoading = false;
const isEnabled = false;
const isEqual = (a, b) => a === b;
2. Enums
2.1 Prefer readonly constant POJO over enums
Not advisable
enum WeekDays {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY,
}
Good
const WEEK_DAYS = {
MONDAY: 'monday',
TUESDAY: 'tuesday',
WEDNESDAY: 'wednesday',
THURSDAY: 'thursday',
FRIDAY: 'friday',
SATURDAY: 'saturday',
SUNDAY: 'sunday',
} as const;
type WeekDays = (typeof WEEK_DAYS)[keyof typeof WEEK_DAYS];
3. Interfaces & Types
3.1 Do not prefix with "I" or "T"
Bad
interface ITextProps {...}
type TAmount = number;
Good
interface TextProps {...}
type Amount = number;
3.2 Prefer interface to type aliases
Use type aliases primarily for Unions, Tuples, or giving primitives meaning.
3.3 Prefer union type over extensions
Bad
interface ProductAmount {
amount: number;
currency: Currency;
country: Country;
}
interface Product extends ProductAmount {
id: Uuid;
name: string;
}
Good
type Product = ProductDetails & ProductAmount;
3.4 Prefer type inference
Good
const getTotalAmount = (prices: number[]) => {
// Return type is inferred
let totalAmount = 0.0;
for (const price of prices) {
totalAmount += price * VAT;
}
return totalAmount;
};
4. Classes
4.1 Method spacing
Methods should be separated with a new line.
4.2 Short constructor syntax
Better
class Person {
constructor(
private name: string,
private age: number,
) {}
}
4.3 Getters and Setters for computed attributes
Better
class Product {
constructor(private priceList: number[]) {}
get totalAmount() {
return this.priceList.reduce((acc, price) => acc + price * VAT, 0);
}
}
5. Generics
5.1 Use descriptive names for generic parameters
Bad
interface Employee<D> {
meta: D;
}
Good
interface Employee<TMeta> {
meta: TMeta;
}
6. Expressions and Conditions
6.1 Avoid complex expressions in IF statements
Bad
if(age > 18 && age <= 90) { ... }
Good
const isAcceptableVotingAge = age > MINIMUM_VOTING_AGE && age <= MAXIMUM_VOTING_AGE;
if(isAcceptableVotingAge) { ... }
6.2 Prefer early returns
Good
const sendEmailRequest = async (email: string) => {
if (isEmpty(email) || !isValidEmail(email)) return;
// send email api request here
};
6.3 Avoid complex ternary operations
Nested or chained ternary operators reduce readability and make debugging difficult. Use if/else statements or early returns instead.
Bad
const getStatusLabel = (status: string) =>
status === 'pending'
? 'Awaiting Review'
: status === 'approved'
? 'Approved'
: status === 'rejected'
? 'Rejected'
: 'Unknown';
const message =
isLoading ? 'Loading...' : hasError ? 'Error occurred' : data ? data.message : 'No data';
Good
const getStatusLabel = (status: string) => {
if (status === 'pending') return 'Awaiting Review';
if (status === 'approved') return 'Approved';
if (status === 'rejected') return 'Rejected';
return 'Unknown';
};
// Or use a lookup object for mappings
const STATUS_LABELS = {
pending: 'Awaiting Review',
approved: 'Approved',
rejected: 'Rejected',
} as const;
const getStatusLabel = (status: string) => STATUS_LABELS[status] ?? 'Unknown';
Good (for simple conditional rendering)
// Simple ternaries are acceptable
const buttonLabel = isSubmitting ? 'Saving...' : 'Save';
// For multiple conditions, extract to a function or use if/else
const getMessage = () => {
if (isLoading) return 'Loading...';
if (hasError) return 'Error occurred';
if (data) return data.message;
return 'No data';
};
const message = getMessage();
7. Components
7.1 Avoid constant components
Bad
const Product: React.FC = ({ name, price }) => { ... }
Good
export function Product({ name, price }: ProductProps) { ... }
7.2 Prefer Readonly<> for Props
Good
interface PlanCardProps {
businessName: string;
id: number;
}
export function PlanCard(props: Readonly<PlanCardProps>) { ... }
8. Import and Exports
8.1 Prefer named exports
Good
export function Product() {...}
8.2 Barrel-export components
Use an index.ts file in your folders to group exports.
// index.ts
export * from './product-card';
export * from './product-price';
9. File Layout
- Import statements
- Interfaces and Type aliases
- Constants
- Exports (Functions/Components)
- Private module functions / variables
10. Code Formatting
10.1 Add newlines before key statements
Add a blank line before return, conditionals (if/else), await, and variable declarations/initializations to improve readability.
Bad
const fetchUserData = async (userId: string) => {
const isValid = validateId(userId);
if (!isValid) {
throw new Error('Invalid user ID');
}
const response = await api.getUser(userId);
const user = response.data;
return user;
};
Good
const fetchUserData = async (userId: string) => {
const isValid = validateId(userId);
if (!isValid) {
throw new Error('Invalid user ID');
}
const response = await api.getUser(userId);
const user = response.data;
return user;
};
Bad
const processOrder = async (order: Order) => {
const items = order.items;
const total = calculateTotal(items);
if (total > MAX_ORDER_AMOUNT) {
return { error: 'Order exceeds maximum amount' };
}
await validateInventory(items);
await chargeCustomer(order.customerId, total);
const confirmation = await createOrderConfirmation(order);
return confirmation;
};
Good
const processOrder = async (order: Order) => {
const items = order.items;
const total = calculateTotal(items);
if (total > MAX_ORDER_AMOUNT) {
return { error: 'Order exceeds maximum amount' };
}
await validateInventory(items);
await chargeCustomer(order.customerId, total);
const confirmation = await createOrderConfirmation(order);
return confirmation;
};