How to Organize Types in a React Project

You've just started a new React project with TypeScript, and you're already feeling overwhelmed. The API documentation is a mess, there's no clear guidance on structuring your types, and the pressure to deliver quickly is mounting. Sound familiar?

Many developers, especially those new to React and TypeScript, face this exact situation. As one developer shared on Reddit, "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."

The good news? You're about to learn a systematic approach to organizing types in your React project that will save you from this frustration.

Why Type Organization Matters

Before diving into the "how," let's understand why proper type organization is crucial:

  1. Maintainability: Well-organized types make your code easier to maintain and update

  2. Reusability: Properly structured types can be reused across different components and features

  3. Team Collaboration: Clear type organization helps team members quickly understand and work with the codebase

  4. Scalability: As your project grows, good type organization prevents your codebase from becoming a tangled mess

The Foundation: Project Structure

Let's start with a solid foundation. Here's a recommended project structure that has proven effective in real-world applications:

my-app/
├── src/
│   ├── types/           # Global type definitions
│   │   ├── index.ts     # Type exports
│   │   ├── api.ts       # API-related types
│   │   └── models.ts    # Data models
│   ├── components/      # React components
│   │   └── Button/
│   │       ├── Button.tsx
│   │       └── types.ts # Component-specific types
│   ├── features/        # Feature-based modules
│   │   └── auth/
│   │       ├── types.ts
│   │       └── components/
│   ├── pages/          # Page components
│   └── utils/          # Utility functions

This structure follows the principle of "organization should increase productivity, not hinder it." It's designed to be intuitive while remaining flexible enough to adapt to your project's specific needs.

Core Strategies for Type Organization

1. Co-locate Types with Their Usage

One of the most effective strategies is to co-locate types with the components or features that use them. As recommended in community discussions, "Co-locate your types first - define them in the place where they're used."

Here's how to implement this:

// src/components/UserProfile/types.ts
export interface UserProfileProps {
  userId: string;
  showAvatar?: boolean;
}

// src/components/UserProfile/UserProfile.tsx
import { UserProfileProps } from './types';

const UserProfile: React.FC<UserProfileProps> = ({ userId, showAvatar }) => {
  // Component implementation
};

2. Create a Global Types Directory

While co-location is preferred for component-specific types, you'll still need a central location for shared types. Create a types directory in your source folder:

// src/types/api.ts
export interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

// src/types/models.ts
export interface User {
  id: string;
  name: string;
  email: string;
}

3. Use Barrel Files for Type Exports

Barrel files (index.ts) make it easier to import multiple types from a single location:

// src/types/index.ts
export * from './api';
export * from './models';

// Usage in components
import { User, ApiResponse } from '@/types';

4. Feature-Based Type Organization

For larger applications, organize types based on features. This approach aligns with the natural structure of your application:

// src/features/auth/types.ts
export interface LoginCredentials {
  email: string;
  password: string;
}

export interface AuthState {
  user: User | null;
  isAuthenticated: boolean;
}

Best Practices for Type Definition

1. Keep Types Simple and Focused

Avoid creating overly complex types. Break down complex types into smaller, more manageable pieces:

// Instead of this
interface UserWithEverything {
  id: string;
  name: string;
  address: {
    street: string;
    city: string;
    country: string;
  };
  orders: Order[];
}

// Do this
interface Address {
  street: string;
  city: string;
  country: string;
}

interface User {
  id: string;
  name: string;
  address: Address;
}

interface UserWithOrders extends User {
  orders: Order[];
}

2. Use TypeScript's Advanced Features Wisely

TypeScript offers powerful features for type manipulation. Use them when they add value:

// Utility types for common patterns
type Nullable<T> = T | null;
type Optional<T> = T | undefined;

// Type guards for runtime type checking
function isUser(obj: any): obj is User {
  return 'id' in obj && 'name' in obj;
}

3. Document Complex Types

Add JSDoc comments to explain complex types or those with non-obvious implications:

/**
 * Represents a user's notification preferences
 * @property email - Email notification settings
 * @property push - Push notification settings
 * @property frequency - How often to send notifications
 */
interface NotificationPreferences {
  email: boolean;
  push: boolean;
  frequency: 'daily' | 'weekly' | 'monthly';
}

Practical Tips for Implementation

1. Start Simple and Evolve

As one developer suggests on Reddit, "I usually start as flat as possible and as the project grows start grouping things in the way that makes the most sense to the nature of the project." This approach prevents over-engineering and allows your type organization to evolve naturally with your project.

2. Use Modern Tools

Modern IDEs and tools can help manage your types effectively:

  • Use VS Code with TypeScript plugins for better type checking and auto-completion

  • Implement ESLint with TypeScript rules to enforce consistent type usage

  • Consider using Prettier for consistent type formatting

3. Consider Using Framework Conventions

If you're starting a new project, consider using established frameworks like Next.js or Remix, as they provide conventions for organizing your code, including types. As noted in community discussions, "If you're starting a new React project you probably want to be using Remix or NextJS and following their conventions."

Common Pitfalls to Avoid

  1. Over-organizing Too Early

    • Don't create complex type hierarchies before they're needed

    • Let the organization evolve with your project's needs

  2. Inconsistent Naming Conventions

    • Stick to a consistent naming pattern for your types

    • Use clear, descriptive names that indicate the purpose of the type

  3. Duplicate Type Definitions

    • Avoid defining the same types in multiple places

    • Use imports and exports to share types across files

Conclusion

Organizing types in a React project doesn't have to be overwhelming. Start with co-location, maintain a clear directory structure, and let your organization evolve naturally with your project. Remember that the goal is to make your code more maintainable and your development process more efficient.

As you implement these strategies, keep in mind that there's no one-size-fits-all solution. The best approach is the one that works for your team and project while maintaining clarity and scalability. Stay flexible and be ready to adjust your organization as your project grows and evolves.

For further reading and inspiration, check out the Bulletproof React project structure guide and the TypeScript documentation for React projects.

Raymond Yeh

Raymond Yeh

Published on 24 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 Should I Organize My Types as a React Developer?

How Should I Organize My Types as a React Developer?

Struggling with messy API responses and scattered type definitions? Learn the battle-tested approach to organizing your React types, from co-location principles to handling inconsistent APIs.

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