Skip to content

Latest commit

 

History

History
78 lines (61 loc) · 3.04 KB

File metadata and controls

78 lines (61 loc) · 3.04 KB

Code Conventions

These conventions must be followed in all code:

TypeScript/JavaScript

Code Structure

  • Group exports at the end of the file in a single export {} block

  • When designing a module, place the calling function at the top of the file, and the child function(s) below it. This improves readability by showing the main logic first.

    // Good: Calling function first
    function mainTask() {
      const result = subTask();
      console.log(result);
    }
    
    function subTask() {
      return "Sub-task completed";
    }
    
    // Bad: Child function first
    function subTask() {
      return "Sub-task completed";
    }
    
    function mainTask() {
      const result = subTask();
      console.log(result);
    }
  • Destructure props directly in the function signature for components and functions

  • When a function accepts multiple arguments (3 or more), prefer passing them as a single object rather than positional arguments. This improves readability and makes adding/removing arguments less error-prone.

    // Good: Single object argument
    interface UserOptions {
      id: number;
      name: string;
      isAdmin?: boolean;
    }
    function createUser({ id, name, isAdmin = false }: UserOptions) {
      // ...
    }
    createUser({ id: 1, name: "Alice" });
    
    // Bad: Multiple positional arguments
    function createUser(id: number, name: string, isAdmin: boolean = false) {
      // ...
    }
    createUser(1, "Alice"); // What is the third argument? Is it optional?

Documentation & Comments

  • Avoid multi-line jsdoc comments when it can fit in a single line
  • All comments should be relevant:
    • Avoid comments that explain simple lines of code (e.g., // Initialize variable x). The code should be self-explanatory.
    • Avoid "working comments" or comments that merely state what the code is doing (e.g., // Updated function call, // Loop through items, // removed xyz from here). These become outdated quickly and add noise.
    • Comments should primarily clarify why something is done a certain way if it's not obvious, or explain complex logic that cannot be simplified further.

Testing

  • Tests should start with the word "should".
  • Tests should be grouped under a __tests__ folder and use the following naming scheme: ${filename}.test.ts.
  • Use TZDate from @date-fns/tz for creating dates within tests to ensure consistent timezone handling, matching the application logic.
  • For time-sensitive tests, use vi.useFakeTimers() and vi.setSystemTime() to control the system clock. Remember to call vi.useRealTimers() in afterEach.
  • Assert specific log messages using the shared capturedOutput array imported from @/utils/createOutputCapture. Clear this array (capturedOutput.length = 0) in beforeEach.
  • For tests involving database interactions, ensure the relevant tables are cleaned up in beforeEach (e.g., await db.delete(coursesSchema)).

Error Handling

  • Use descriptive error messages that explain what went wrong
  • Prefer custom error classes for specific error types
  • Always log errors with appropriate context