How Should I Organize My Types as a React Developer?

You've just joined a new React project and you're staring at a mess of inconsistent API responses, poorly structured types, and a codebase that seems to follow no clear organization pattern. Your heart sinks as you realize you'll need to spend countless hours just figuring out where to put your type definitions and how to manage them effectively.

Sound familiar? You're not alone. Many developers, especially those new to React and TypeScript, struggle with organizing their types in a way that makes sense and scales well with their projects.

The Challenge of Type Organization

The reality is that many React projects start simple but quickly become complex beasts. You might begin with a few basic interfaces, but soon you're dealing with:

  • Inconsistent API responses that return different shapes of data for the same endpoint

  • Multiple joined tables and nested object structures

  • Random fields that appear and disappear depending on the context

  • Legacy code that doesn't follow any clear typing patterns

One developer shared their experience: "I've come from a project where the API was an absolute mess. First job, first project, first time using React, no one to help. At the time, I spent an entire week researching libraries, tools, folder structures. Anything that could help me make it work."

The Foundation: Basic Project Structure

Before diving into type organization, let's establish a solid foundation. A well-organized React project typically follows this structure:

src/
├── components/
├── pages/
├── hooks/
├── utils/
├── types/
├── App.tsx
└── index.tsx

This structure provides a clear separation of concerns while maintaining flexibility. However, the real challenge isn't just creating folders—it's deciding how to organize your types within this structure.

The First Rule: Co-location

The single most important principle in type organization is co-location: define your types where they're used. This means:

  • Component props types should live in the component file

  • API response types should live near the API calls

  • Shared types should live in a dedicated types folder

This approach solves one of the biggest pains developers face: constantly jumping between files to understand how types are related. As one experienced developer puts it, "Co-locate your types first - define them in the place where they're used."

Practical Implementation

Let's look at how to implement these principles in practice.

1. Component-Level Types

For component types, keep them in the same file as the component:

// UserProfile.tsx
interface UserProfileProps {
  user: {
    id: number;
    name: string;
    email: string;
  };
  onEdit: () => void;
}

export const UserProfile: React.FC<UserProfileProps> = ({ user, onEdit }) => {
  // Component implementation
};

2. Shared Types

For types used across multiple components, create a dedicated types file in your types directory:

// types/user.ts
export interface User {
  id: number;
  name: string;
  email: string;
  preferences?: UserPreferences;
}

export interface UserPreferences {
  theme: 'light' | 'dark';
  notifications: boolean;
}

3. API Response Types

When dealing with API responses, especially inconsistent ones, create interface maps that handle different response shapes:

// api/types.ts
interface BaseResponse<T> {
  data: T;
  status: number;
  message?: string;
}

interface UserResponse extends BaseResponse<User> {
  metadata?: {
    lastLogin: string;
    sessionId: string;
  };
}

Best Practices for Type Management

1. Use TypeScript's Advanced Features

TypeScript offers powerful features to help manage complex types:

// Partial types for optional updates
type UserUpdate = Partial<User>;

// Union types for variant handling
type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;

// Utility types for better type safety
type RequiredUserFields = Required<Pick<User, 'id' | 'email'>>;

2. Avoid Common Pitfalls

Don't fall into these common traps:

  • Using any as an escape hatch

  • Over-generalizing types that should be specific

  • Creating deeply nested type structures

  • Not documenting complex type relationships

Advanced Organization Strategies

Feature-Based Organization

For larger applications, consider organizing types by feature rather than type:

src/
├── features/
│   ├── user/
│   │   ├── types.ts
│   │   ├── UserProfile.tsx
│   │   └── UserSettings.tsx
│   └── product/
│       ├── types.ts
│       ├── ProductList.tsx
│       └── ProductDetail.tsx
└── shared/
    └── types/
        ├── common.ts
        └── api.ts

This approach makes it easier to:

  • Locate related code and types

  • Maintain feature isolation

  • Scale the application without confusion

Type Organization for Different Project Sizes

Small Projects (1-5 developers)
  • Keep it simple with co-located types

  • Use a single shared types file for common interfaces

  • Avoid over-engineering the structure

Medium Projects (5-15 developers)
  • Implement feature-based organization

  • Create clear conventions for type naming and location

  • Use barrel exports for convenient importing

Large Projects (15+ developers)
  • Consider a monorepo approach with shared type packages

  • Implement strict type validation and documentation

  • Use automated tools to enforce type organization patterns

Handling Complex Scenarios

1. Inconsistent APIs

When dealing with inconsistent APIs (a common pain point mentioned by developers), create adapter types:

// api/adapters.ts
interface RawUserResponse {
  // Type matching the actual API response
  user_id: number;
  user_name: string;
  user_email?: string;
}

interface NormalizedUser {
  // Your application's consistent user type
  id: number;
  name: string;
  email: string | null;
}

function normalizeUser(raw: RawUserResponse): NormalizedUser {
  return {
    id: raw.user_id,
    name: raw.user_name,
    email: raw.user_email || null,
  };
}

2. Dynamic Types

For situations where types need to be dynamic, use generics and conditional types:

type DynamicResponse<T extends 'user' | 'product'> = {
  user: UserResponse;
  product: ProductResponse;
}[T];

function fetchData<T extends 'user' | 'product'>(
  type: T
): Promise<DynamicResponse<T>> {
  // Implementation
}

Tools and Resources

1. TypeScript Configuration

Optimize your TypeScript configuration for better type organization:

{
  "compilerOptions": {
    "strict": true,
    "baseUrl": "src",
    "paths": {
      "@types/*": ["types/*"],
      "@components/*": ["components/*"]
    }
  }
}

2. VS Code Extensions

Install these helpful extensions for better type management:

  • TypeScript Hero: Organizes your imports

  • Pretty TypeScript Errors: Makes type errors more readable

  • TypeScript Import Sorter: Keeps your type imports organized

Conclusion

Organizing types in a React project doesn't have to be overwhelming. Start with these key principles:

  1. Co-locate types with their usage

  2. Create shared types only when necessary

  3. Use feature-based organization for larger projects

  4. Implement consistent naming conventions

  5. Leverage TypeScript's advanced features

Remember what one developer wisely noted: "Organization is supposed to increase your productivity and quality, not get in the way of it." The best type organization system is one that works for your team and makes development easier, not harder.

As your project grows, be prepared to evolve your type organization strategy. What works for a small project might not scale to a larger one, and that's okay. The key is to maintain consistency and clarity while remaining flexible enough to adapt to your project's changing needs.

Additional Resources

Remember, the goal isn't perfection but rather creating a maintainable and scalable system that helps your team work effectively. Start with these principles, adapt them to your needs, and iterate as your project grows.

Raymond Yeh

Raymond Yeh

Published on 10 March 2025

Get engineers' time back from marketing!

Don't let managing a blog on your site get in the way of your core product.

Wisp empowers your marketing team to create and manage content on your website without consuming more engineering hours.

Get started in few lines of codes.

Choosing a CMS
Related Posts
How to Organize Types in a React Project

How to Organize Types in a React Project

Feeling overwhelmed with TypeScript in your React project? Learn a systematic approach to organizing types that will save you from messy APIs and folder structure confusion.

Read Full Story
The Ultimate Guide to Organizing Your Next.js 15 Project Structure

The Ultimate Guide to Organizing Your Next.js 15 Project Structure

Comprehensive guide to Next.js 15 folder structure: Learn how to organize App Router, components, utils, and lib folders. Includes monorepo setup with pnpm and Turborepo.

Read Full Story
What Senior Developers Should Know About TypeScript - A Guide with Code Examples

What Senior Developers Should Know About TypeScript - A Guide with Code Examples

Elevate your TypeScript skills with our advanced guide. Explore Conditional Types, Mapped Types, and best practices to enhance code quality and maintainability in large-scale projects.

Read Full Story
Loading...