Skip to content

TypeScript

This document provides a comprehensive guide for using TypeScript in our large-scale React applications, emphasizing strong typing, structured organization, and best practices for enhancing code quality and maintainability.

Strong Typing for Component Props

  • Strongly Typed Props: Ensure all React component props are strongly typed. Use TypeScript interfaces or types to define prop shapes.

Use of Interface for Props

  • Default to Interface: Use interfaces for component props definitions by default.
  • Switch to Type When Needed: Use type for props when utility types like Partial, Readonly, or union types are required.

Typing API Responses

  • Strong Typing for Responses: All API responses should be typed. Use interfaces or types to define the shape of the response.
  • JSDoc Annotations: Include JSDoc annotations describing the API being called, for better readability and maintainability.
// Example of a typed API response with JSDoc annotation
/**
* Fetch user data
* @returns {Promise<NonPaginatedAPIResponse<User>>}
* GET /api/software-tracking/user
*/
const routeFactory = (path?: string) => {
return `software-tracking${path ? '/' + path : ''}`
}
// inside the service
export class SoftwareService {
static async fetchUserData(): Promise<NonPaginatedAPIResponse<User>> {
// API call logic...
const response = await axios.get(routeFactory('user'))
return response.data
}
}

Utilizing Helper Types

In TypeScript, helper types can greatly simplify and standardize common patterns in your code. Below are examples of how we use helper types for common data structures, such as paginated API responses.

// TypeScript helper types for API responses
/**
* Represents a paginated API response
* @template T The type of data in the response
*/
export type PaginatedAPIResponse<T> = {
data: T
meta_data: PaginatedMetaData
selected?: T
success: boolean
}
/**
* Represents a non-paginated API response
* @template T The type of data in the response
*/
export type NonPaginatedAPIResponse<T> = {
data: T
success: boolean
}
/**
* Detailed information about pagination metadata
*/
export type PaginatedMetaData = {
total_items: number
page_no: number
items_on_page: number
}

Best Practices for Organizing Types

Organizing type definitions effectively is key to maintaining a scalable and manageable codebase in TypeScript, especially for large-scale React applications. Here are some best practices to follow:

Centralized Type Definitions

  • Central Repository: Store all TypeScript types and interfaces in a central location, typically in a types/ directory at the root of your project. This makes it easier to find and manage your types.

Feature-Specific Files

  • Modular Approach: Create separate files for each feature or component in your application. For instance, types related to user management could be stored in a user-management.ts file.

Naming Conventions

  • Consistent Naming: Use a consistent naming pattern for your type definition files, like feature-name.ts. This approach helps in quickly identifying the types related to specific features or components.
  • Descriptive File Names: Choose file names that clearly describe the types they contain. Avoid generic names to prevent confusion.

Example of Organized Type Definitions

Consider the following structure as an example for organizing your TypeScript types:

types/user-management.ts
// Example file structure for TypeScript types
export interface User {
id: number
name: string
email: string
}
// types/product.ts
export interface Product {
id: number
name: string
price: number
}