JavaScript & TypeScript Guide

Best practices for writing modern, maintainable, and robust code using JavaScript and TypeScript.

Embrace TypeScript

TypeScript is a superset of JavaScript that adds static types. Using TypeScript is non-negotiable for new projects as it significantly improves code quality. Type safety catches common errors during development, not in production. It makes code easier to read, understand, and refactor, and provides excellent autocompletion in code editors.

interface User {
  id: number;
  name: string;
  isActive: boolean;
}

function promoteUser(user: User) {
  // The user object is guaranteed to have the defined properties.
  console.log(`Promoting ${user.name}`);
}
Coding Standards & Formatting

Consistency is key. We enforce a consistent coding style using Prettier for automatic code formatting and ESLint for identifying problematic patterns in the code. Ensure you have the corresponding extensions installed and configured in your editor to format on save.

Variable Declarations: `let` and `const`

Prefer `const` over `let`. Use `const` for all variables that will not be reassigned. This helps prevent accidental reassignments and makes the code easier to reason about. Use `let` only when you know a variable's value needs to change.

// Good
const MAX_RETRIES = 3;
let currentAttempt = 0;

// Avoid
var oldStyleVariable = '...'; // Avoid using var due to its function-scoping rules.
Asynchronous Code with async/await

Use `async/await` for handling asynchronous operations. It provides a much cleaner and more readable syntax than traditional Promise `.then()` and `.catch()` chains. Always wrap `await` calls in a `try...catch` block to handle potential errors gracefully.

async function fetchData(url: string) {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Failed to fetch data:', error);
    // Handle the error appropriately in the UI
    return null;
  }
}
Modular Code and Imports

Write small, focused modules (files) that do one thing well. This improves reusability and testability. Keep your imports organized by grouping them. A common convention is to group imports from external libraries, then your own application modules, and finally type imports.

import React, { useState } from 'react';
import { Button } from '@/components/ui/button';
import { getUserProfile } from '@/services/userService';
import type { User } from '@/types/user';
React Component Best Practices

When building React components, adhere to the Single Responsibility Principle: a component should do one thing and do it well. Always use functional components with Hooks. Define prop types clearly using TypeScript interfaces. Keep components small and compose them to build more complex UIs. This makes them easier to test, reuse, and maintain.

Write Meaningful Unit Tests

All new features and bug fixes must be accompanied by unit tests. Good tests act as a safety net against regressions and serve as living documentation for how your code is supposed to behave. We use Jest and React Testing Library.

import { sum } from './math';

// Example of a simple test
describe('sum', () => {
  it('should add 1 + 2 to equal 3', () => {
    expect(sum(1, 2)).toBe(3);
  });
});