Skip to main content

best-practices-nodejs

Best Practices for TypeScript in Node.js:

Use TypeScript’s Node Definitions:

Install the @types/node package to your Node.js project to get TypeScript definitions. This gives you type checking and autocomplete for Node.js APIs.

  • Code Example:
    npm install --save-dev @types/node

Configure tsconfig.json Properly:

The tsconfig.json file is where you set TypeScript options. For Node.js, you typically use CommonJS modules and target the version of ECMAScript supported by your Node.js environment.

  • Code Example:
    {
    "compilerOptions": {
    "module": "commonjs",
    "target": "es2019",
    // ... other options
    }
    }

Keep TypeScript Updated:

Using the latest TypeScript version means you have the newest features and the best type safety. Update regularly to keep your project current.

  • Code Example:
    npm install typescript@latest --save-dev

Leverage Path Aliases:

Path aliases let you create shortcuts for imports. This can make your import statements shorter and easier to manage, especially in large projects.

  • Code Example:
    {
    "compilerOptions": {
    "baseUrl": "./", // This must be specified if "paths" is.
    "paths": {
    "@models/*": ["src/models/*"],
    "@utils/*": ["src/utils/*"]
    }
    }
    }

Implement Interface Segregation:

The Interface Segregation Principle suggests that no client should be forced to depend on methods it does not use. Split large interfaces into smaller, more specific ones.

  • Code Example:

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

    interface UserManager {
    createUser(user: User): void;
    deleteUser(userId: number): void;
    }

    // Instead of one large interface, we have two focused ones.

Avoid any and unknown Unless Necessary:

Use specific types instead of any or unknown whenever possible. This helps TypeScript protect you with its static typing.

  • Code Example:

    function getItem(id: number): unknown {
    // Some logic to return an item
    }

    // 'unknown' is safer than 'any', but you should still try to avoid it by specifying a more specific type.

Use TypeScript’s Strict Mode:

Strict mode makes type checking tougher and can reveal potential issues sooner. Turn it on in your TypeScript configuration for better type safety.

  • Code Example:
    {
    "compilerOptions": {
    "strict": true,
    // ... other options
    }
    }

Type Third-Party Modules:

For third-party modules, use type definitions from DefinitelyTyped. If the types you need don't exist, consider adding them to DefinitelyTyped to help others.

  • Code Example:
    npm install @types/express --save-dev

Create Custom Types for Complex Objects:

When you're working with complex objects, especially those used for configuration or environment variables, define custom types to provide clear expectations and improve safety.

  • Code Example:
    type ServerConfig = {
    port: number;
    hostname: string;
    protocol: 'http' | 'https';
    };

Type Error Handling:

In your try/catch blocks, you can type the error to better handle different kinds of errors.

  • Code Example:
    try {
    // some operation that may fail
    } catch (error: unknown) {
    if (error instanceof MyCustomError) {
    // handle custom error
    }
    }

Use ts-node for Development:

ts-node allows you to run TypeScript files directly without precompiling them, which can speed up development.

  • Code Example:
    npx ts-node src/index.ts

Optimize the Build Process:

Enable the incremental option in your tsconfig.json to speed up your build process by only recompiling files that have changed.

  • Code Example:
    {
    "compilerOptions": {
    "incremental": true,
    // ... other options
    }
    }

Use Promises and Async/Await:

Instead of callbacks, use async/await for cleaner, more readable asynchronous code.

  • Code Example:
    async function fetchData() {
    const data = await fetch('https://api.example.com/data');
    // more code to process data
    }

Apply TSLint or ESLint:

Use ESLint with TypeScript for static code analysis to catch common mistakes and enforce coding standards.

  • Code Example:
    npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

Type Guarding:

Type guards allow you to ensure that a variable is of a certain type within a specific block of code.

  • Code Example:

    function isString(value: unknown): value is string {
    return typeof value === 'string';
    }

    if (isString(myVar)) {
    console.log(myVar.toUpperCase()); // safe to use string methods
    }