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.

  • Strongly Typed Props: Ensure all React component props are strongly typed. Use TypeScript interfaces or types to define prop shapes.
  • 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.
  • 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
}
}

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
}

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:

  • 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.
  • 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.
  • 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.

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
}