Skip to content

文件命名规范 - React项目文件命名完全指南

1. 通用命名原则

1.1 核心原则

typescript
const namingPrinciples = {
  一致性: '整个项目保持统一的命名风格',
  描述性: '文件名应清晰描述其内容和用途',
  可搜索性: '便于通过文件名快速查找',
  避免歧义: '避免使用容易混淆的名称',
  遵循约定: '遵循React和TypeScript社区约定'
};

1.2 命名风格

typescript
const namingStyles = {
  PascalCase: {
    用途: 'React组件、类、接口、类型别名',
    示例: ['Button.tsx', 'UserProfile.tsx', 'IUser.ts', 'FormData.types.ts']
  },
  camelCase: {
    用途: '工具函数、普通变量、对象方法',
    示例: ['formatDate.ts', 'validateEmail.ts', 'getUserData.ts']
  },
  'kebab-case': {
    用途: '目录名、CSS文件、配置文件',
    示例: ['user-profile/', 'button.module.css', 'jest.config.js']
  },
  SCREAMING_SNAKE_CASE: {
    用途: '常量、环境变量',
    示例: ['API_ENDPOINTS.ts', 'DEFAULT_CONFIG.ts', '.env']
  }
};

2. 组件文件命名

2.1 React组件

typescript
// ✅ 推荐: PascalCase
Button.tsx
Input.tsx
UserProfile.tsx
ProductCard.tsx
NavigationBar.tsx
SidebarMenu.tsx

// ❌ 不推荐
button.tsx              // 应该使用PascalCase
user-profile.tsx        // 应该使用PascalCase
BUTTON.tsx              // 全大写不推荐
ButtonComponent.tsx     // 不需要Component后缀

2.2 组件目录结构

// 方式1: 单文件组件
components/
├── Button.tsx
├── Input.tsx
└── Modal.tsx

// 方式2: 目录结构 (推荐用于复杂组件)
components/
├── Button/
│   ├── Button.tsx          // 主组件
│   ├── Button.test.tsx     // 测试
│   ├── Button.stories.tsx  // Storybook
│   ├── Button.module.css   // 样式
│   ├── Button.types.ts     // 类型
│   └── index.ts            // 导出
├── Modal/
│   ├── Modal.tsx
│   ├── ModalHeader.tsx     // 子组件
│   ├── ModalBody.tsx
│   ├── ModalFooter.tsx
│   ├── Modal.test.tsx
│   ├── Modal.types.ts
│   └── index.ts
└── UserProfile/
    ├── UserProfile.tsx
    ├── UserAvatar.tsx      // 专属子组件
    ├── UserInfo.tsx
    ├── UserProfile.test.tsx
    └── index.ts

2.3 特殊组件命名

typescript
// 页面组件 (Page suffix可选)
HomePage.tsx       // 或 Home.tsx
AboutPage.tsx      // 或 About.tsx
DashboardPage.tsx  // 或 Dashboard.tsx

// 布局组件
MainLayout.tsx
DashboardLayout.tsx
AuthLayout.tsx

// 容器组件 (Container suffix)
UserListContainer.tsx
ProductGridContainer.tsx

// HOC (高阶组件)
withAuth.tsx
withTheme.tsx
withErrorBoundary.tsx

// Render Props组件
MouseTracker.tsx
DataProvider.tsx

3. Hook文件命名

3.1 自定义Hook

typescript
// ✅ 推荐: use + PascalCase
useAuth.ts
useTheme.ts
useLocalStorage.ts
useFetch.ts
useDebounce.ts
useWindowSize.ts
useIntersectionObserver.ts

// ❌ 不推荐
auth.ts               // 缺少use前缀
UseAuth.ts            // 首字母应该小写
use-auth.ts           // 应该使用camelCase
authHook.ts           // 不需要Hook后缀

3.2 Hook目录结构

hooks/
├── useAuth.ts           // 单文件Hook
├── useFetch/
│   ├── useFetch.ts      // Hook实现
│   ├── useFetch.test.ts
│   ├── useFetch.types.ts
│   └── index.ts
├── useLocalStorage/
│   ├── useLocalStorage.ts
│   ├── useLocalStorage.test.ts
│   └── index.ts
└── index.ts             // 统一导出

3.3 Hook分类命名

typescript
// 状态管理Hooks
useStore.ts
useAppState.ts
useUserState.ts

// 数据获取Hooks
useFetch.ts
useQuery.ts
useUsers.ts
useProducts.ts

// UI交互Hooks
useToggle.ts
useModal.ts
useDropdown.ts

// 浏览器API Hooks
useLocalStorage.ts
useSessionStorage.ts
useGeolocation.ts
useMediaQuery.ts

// 工具Hooks
useDebounce.ts
useThrottle.ts
usePrevious.ts
useInterval.ts

4. 类型文件命名

4.1 TypeScript类型

typescript
// 方式1: .types.ts后缀 (推荐)
user.types.ts
api.types.ts
common.types.ts
button.types.ts

// 方式2: .d.ts (声明文件)
global.d.ts
custom.d.ts
window.d.ts

// ✅ 推荐结构
types/
├── user.types.ts        // 用户相关类型
├── api.types.ts         // API相关类型
├── common.types.ts      // 通用类型
├── product.types.ts
└── index.ts             // 统一导出

// 组件内联类型
Button/
├── Button.tsx
├── Button.types.ts      // 组件专属类型
└── index.ts

4.2 类型文件内容

typescript
// user.types.ts
export interface User {
  id: string;
  name: string;
  email: string;
  avatar?: string;
}

export interface UserProfile extends User {
  bio: string;
  location: string;
  website?: string;
}

export type UserRole = 'admin' | 'user' | 'guest';

export type UserStatus = 'active' | 'inactive' | 'banned';

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

export interface ApiError {
  code: string;
  message: string;
  details?: unknown;
}

export interface PaginatedResponse<T> {
  items: T[];
  total: number;
  page: number;
  pageSize: number;
}

// common.types.ts
export type Nullable<T> = T | null;
export type Optional<T> = T | undefined;
export type Maybe<T> = T | null | undefined;

export type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

5. 样式文件命名

5.1 CSS/SCSS文件

typescript
// CSS Modules (推荐)
Button.module.css
Input.module.css
UserProfile.module.scss

// 全局样式
global.css
variables.css
reset.css
typography.css

// 主题样式
theme.css
dark-theme.css
light-theme.css

// 工具样式
utilities.css
helpers.css

5.2 Styled Components

typescript
// 方式1: .styles.ts/.styles.tsx
Button.styles.ts
Input.styles.tsx
UserProfile.styles.ts

// 方式2: styled前缀
styledButton.ts
styledInput.ts

// ✅ 推荐结构
Button/
├── Button.tsx
├── Button.styles.ts     // Styled Components
├── Button.types.ts
└── index.ts

// Button.styles.ts示例
import styled from 'styled-components';

export const StyledButton = styled.button`
  padding: 10px 20px;
  background-color: ${props => props.theme.primary};
`;

export const ButtonText = styled.span`
  font-weight: bold;
`;

6. 测试文件命名

6.1 测试文件

typescript
// 单元测试
Button.test.tsx          // 或 Button.spec.tsx
formatDate.test.ts       // 或 formatDate.spec.ts
useAuth.test.ts

// 集成测试
UserFlow.integration.test.tsx
CartFlow.integration.test.ts

// E2E测试
login.e2e.test.ts
checkout.e2e.test.ts

// 测试工具
testUtils.ts
mockData.ts
testSetup.ts

6.2 测试目录结构

// 方式1: 测试文件与源文件同目录 (推荐)
components/
├── Button/
│   ├── Button.tsx
│   ├── Button.test.tsx
│   └── index.ts

// 方式2: 独立tests目录
src/
├── components/
│   └── Button/
│       ├── Button.tsx
│       └── index.ts
└── __tests__/
    └── components/
        └── Button.test.tsx

// 方式3: 根目录tests
tests/
├── unit/
│   ├── components/
│   │   └── Button.test.tsx
│   └── utils/
│       └── formatDate.test.ts
├── integration/
│   └── UserFlow.test.tsx
└── e2e/
    └── login.test.ts

7. 工具和服务文件命名

7.1 工具函数

typescript
// utils/
formatDate.ts            // camelCase
validateEmail.ts
generateId.ts
debounce.ts
throttle.ts
classNames.ts

// 数学工具
mathUtils.ts
calculations.ts

// 字符串工具
stringUtils.ts
textHelpers.ts

// ❌ 不推荐
Utils.ts                 // 太泛化
helper.ts                // 不够描述性
functions.ts             // 太泛化

7.2 API服务

typescript
// services/
userApi.ts              // 或 userService.ts
authApi.ts
productApi.ts
orderApi.ts

// 或按功能组织
services/
├── api/
│   ├── userApi.ts
│   ├── authApi.ts
│   └── productApi.ts
├── storage/
│   ├── localStorage.ts
│   └── sessionStorage.ts
└── analytics/
    ├── googleAnalytics.ts
    └── trackingService.ts

7.3 HTTP客户端

typescript
// API客户端
apiClient.ts
httpClient.ts
axiosInstance.ts

// 拦截器
requestInterceptor.ts
responseInterceptor.ts
errorInterceptor.ts

8. 配置和常量文件

8.1 常量文件

typescript
// constants/
API_ENDPOINTS.ts         // SCREAMING_SNAKE_CASE
ROUTES.ts
ERROR_MESSAGES.ts
DEFAULT_VALUES.ts
REGEX_PATTERNS.ts

// 或按功能分组
constants/
├── api/
│   ├── ENDPOINTS.ts
│   └── HEADERS.ts
├── routes/
│   └── PATHS.ts
└── validation/
    └── RULES.ts

8.2 配置文件

typescript
// config/
env.ts                   // 环境配置
theme.ts                 // 主题配置
i18n.ts                  // 国际化配置
routes.ts                // 路由配置

// 第三方库配置
axiosConfig.ts
reactQueryConfig.ts
sentryConfig.ts

9. 状态管理文件命名

9.1 Redux

typescript
// Redux Toolkit
store/
├── index.ts
├── hooks.ts             // 类型化hooks
├── slices/
│   ├── userSlice.ts
│   ├── authSlice.ts
│   └── productSlice.ts
└── middleware/
    ├── loggerMiddleware.ts
    └── errorMiddleware.ts

// 传统Redux
store/
├── index.ts
├── actions/
│   ├── userActions.ts
│   └── authActions.ts
├── reducers/
│   ├── userReducer.ts
│   ├── authReducer.ts
│   └── rootReducer.ts
├── selectors/
│   ├── userSelectors.ts
│   └── authSelectors.ts
└── types/
    ├── actionTypes.ts
    └── stateTypes.ts

9.2 Zustand/Jotai

typescript
// Zustand
store/
├── useUserStore.ts      // use前缀
├── useAuthStore.ts
└── useCartStore.ts

// Jotai
atoms/
├── userAtoms.ts         // Atoms后缀
├── authAtoms.ts
└── cartAtoms.ts

10. 资源文件命名

10.1 图片文件

typescript
// 图片命名: kebab-case
assets/
├── images/
│   ├── logo.png
│   ├── user-avatar.jpg
│   ├── product-thumbnail.png
│   ├── banner-home.jpg
│   ├── icon-search.svg
│   └── icon-menu.svg
└── icons/
    ├── arrow-left.svg
    ├── arrow-right.svg
    ├── check-mark.svg
    └── close-button.svg

10.2 字体文件

typescript
assets/
└── fonts/
    ├── roboto-regular.woff2
    ├── roboto-bold.woff2
    ├── open-sans-regular.woff2
    └── open-sans-bold.woff2

11. 文档文件命名

typescript
// Markdown文档
README.md
CONTRIBUTING.md
CHANGELOG.md
LICENSE.md
API.md

// 组件文档
components/
└── Button/
    ├── Button.tsx
    ├── Button.md         // 组件文档
    └── Button.stories.tsx

12. 命名禁忌

typescript
const namingDontS = {
  避免缩写: {
    ❌: ['usr.ts', 'btn.tsx', 'usr-prof.tsx'],
    ✅: ['user.ts', 'Button.tsx', 'UserProfile.tsx']
  },
  避免数字后缀: {
    ❌: ['Button1.tsx', 'Modal2.tsx', 'utils2.ts'],
    ✅: ['PrimaryButton.tsx', 'ConfirmModal.tsx', 'stringUtils.ts']
  },
  避免无意义前缀: {
    ❌: ['myButton.tsx', 'theModal.tsx', 'aUtils.ts'],
    ✅: ['Button.tsx', 'Modal.tsx', 'utils.ts']
  },
  避免过长名称: {
    ❌: ['UserProfileComponentWithAvatarAndEditButton.tsx'],
    ✅: ['UserProfile.tsx', 'UserProfileCard.tsx']
  },
  避免特殊字符: {
    ❌: ['user&profile.ts', 'button@v2.tsx', 'modal#new.tsx'],
    ✅: ['userProfile.ts', 'ButtonV2.tsx', 'NewModal.tsx']
  }
};

13. 命名检查清单

typescript
const namingChecklist = {
  组件文件: [
    '✅ 使用PascalCase',
    '✅ .tsx扩展名',
    '✅ 名称描述组件功能',
    '✅ 避免Component后缀',
    '✅ 一致的子组件命名'
  ],
  Hook文件: [
    '✅ use前缀 + camelCase',
    '✅ .ts或.tsx扩展名',
    '✅ 描述Hook功能',
    '✅ 避免Hook后缀'
  ],
  工具文件: [
    '✅ 使用camelCase',
    '✅ .ts扩展名',
    '✅ 动词开头描述功能',
    '✅ 避免Utils后缀'
  ],
  类型文件: [
    '✅ .types.ts后缀',
    '✅ camelCase文件名',
    '✅ PascalCase类型名',
    '✅ 清晰的类型描述'
  ],
  常量文件: [
    '✅ SCREAMING_SNAKE_CASE',
    '✅ .ts扩展名',
    '✅ 描述常量用途',
    '✅ 复数形式(如APIs, ROUTEs)'
  ],
  测试文件: [
    '✅ .test.ts或.spec.ts后缀',
    '✅ 与源文件名称匹配',
    '✅ 描述测试场景',
    '✅ 组织在合理位置'
  ]
};

14. 自动化工具

14.1 文件命名Linter

javascript
// .eslintrc.js
module.exports = {
  plugins: ['filenames'],
  rules: {
    'filenames/match-regex': [2, '^[A-Z][a-zA-Z]*$', true],  // 组件文件
    'filenames/match-exported': [2, 'camel']                  // 导出匹配
  }
};

14.2 命名验证脚本

javascript
// scripts/validate-naming.js
const fs = require('fs');
const path = require('path');

function validateComponentNaming(filePath) {
  const fileName = path.basename(filePath, '.tsx');
  
  // 检查PascalCase
  if (!/^[A-Z][a-zA-Z0-9]*$/.test(fileName)) {
    console.error(`❌ ${filePath}: 组件文件名应使用PascalCase`);
    return false;
  }
  
  // 检查文件内容是否有同名导出
  const content = fs.readFileSync(filePath, 'utf-8');
  const hasExport = content.includes(`export function ${fileName}`) ||
                    content.includes(`export const ${fileName}`);
  
  if (!hasExport) {
    console.warn(`⚠️  ${filePath}: 文件名与导出不匹配`);
  }
  
  return true;
}

function validateHookNaming(filePath) {
  const fileName = path.basename(filePath, '.ts');
  
  // 检查use前缀
  if (!fileName.startsWith('use')) {
    console.error(`❌ ${filePath}: Hook文件名应以use开头`);
    return false;
  }
  
  // 检查camelCase
  if (!/^use[A-Z][a-zA-Z0-9]*$/.test(fileName)) {
    console.error(`❌ ${filePath}: Hook文件名应使用camelCase`);
    return false;
  }
  
  return true;
}

15. 总结

文件命名规范的核心要点:

  1. 组件: PascalCase + .tsx
  2. Hooks: use + camelCase + .ts
  3. 工具: camelCase + .ts
  4. 类型: .types.ts后缀
  5. 常量: SCREAMING_SNAKE_CASE
  6. 样式: .module.css/.styles.ts
  7. 测试: .test.ts/.spec.ts
  8. 目录: kebab-case

保持一致的命名规范能显著提升代码可读性和团队协作效率。