阿里云主机折上折
  • 微信号
Current Site:Index > Module best practices

Module best practices

Author:Chuan Chen 阅读数:52586人阅读 分类: TypeScript

TypeScript's module system provides powerful tools for code organization. Proper use of modules can significantly improve a project's maintainability and scalability. Below, we explore core modularization practices from multiple dimensions.

Module Division Principles

Module division should follow the principle of high cohesion and low coupling. A common mistake is cramming unrelated functionalities into the same module:

// Bad example: Utility functions mixed with business logic
export function formatDate(date: Date): string {
  return date.toISOString()
}

export class UserService {
  async login() { /*...*/ }
}

The improved approach involves splitting by functional boundaries:

// utils/date.ts
export function formatDate(date: Date): string {
  return date.toISOString()
}

// services/user.ts
export class UserService {
  async login() { /*...*/ }
}

Export Strategy Optimization

Avoid default exports for three reasons:

  1. Renaming can lead to ambiguity
  2. Auto-import tools may struggle to identify them accurately
  3. Refactoring can easily break references

Prefer named exports:

// Recommended approach
export const API_TIMEOUT = 5000
export interface UserProfile { /*...*/ }
export function fetchUser() { /*...*/ }

// Explicit import paths in usage
import { API_TIMEOUT, fetchUser } from './api'

Circular Dependency Handling

TypeScript has limited detection for circular dependencies. Avoid them by:

  1. Extracting common types to standalone modules
  2. Using dependency injection patterns
  3. Implementing lazy loading
// Solution example: Dependency injection
class AuthService {
  constructor(private userService: UserService) {}
}

class UserService {
  private authService?: AuthService
  setAuthService(service: AuthService) {
    this.authService = service
  }
}

Path Alias Configuration

In large projects, relative paths can cause confusion. Configure tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@utils/*": ["utils/*"],
      "@models/*": ["models/*"]
    }
  }
}

Usage example:

import { formatDate } from '@utils/date'
import type { User } from '@models/user'

Dynamic Import Practices

Lazy loading modules significantly improves application performance:

// Dynamically load a rich-text editor
async function loadEditor() {
  const { MarkdownEditor } = await import('@components/editor')
  return MarkdownEditor
}

// Using with React Suspense
const Editor = React.lazy(() => import('@components/editor'))

Type Export Standards

Modules should explicitly export type definitions to avoid implicit type leakage:

// Correct approach: Explicit type exports
export interface Config {
  env: 'dev' | 'prod'
  debug: boolean
}

export function initApp(config: Config) { /*...*/ }

// Bad practice: Implicit parameter type exposure
export function initApp(config: { env: string }) { /*...*/ }

Module Testing Strategy

Maintain independence when writing tests for modules:

// Test example using Jest
import { formatDate } from '@utils/date'

describe('date utils', () => {
  it('should format ISO string', () => {
    const date = new Date('2023-01-01')
    expect(formatDate(date)).toMatch(/2023-01-01/)
  })
})

Module Documentation Standards

Enhance type hints with JSDoc:

/**
 * User permission verification module
 * @module services/auth
 */

/**
 * Checks current user permissions
 * @param {string} permission - Permission code
 * @returns {Promise<boolean>} Whether permission is granted
 */
export async function checkPermission(permission: string): Promise<boolean> {
  // ...
}

Module Version Management

Implement version control for public modules:

  1. Use changesets for changelog management
  2. Follow semantic versioning
  3. Develop private modules using npm link
# Typical workflow
npx changeset add
npx changeset version
npm publish

Module Performance Optimization

Analyze module size with bundling tools:

// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    visualizer({
      open: true,
      gzipSize: true
    })
  ]
})

Hot Module Reload Configuration

Optimize HMR experience in development:

// Custom HMR logic
if (import.meta.hot) {
  import.meta.hot.accept('./module', (newModule) => {
    newModule?.applyUpdate()
  })
}

Cross-Platform Module Design

Consider multi-platform support when designing reusable modules:

// Platform abstraction layer design
export abstract class Storage {
  abstract getItem(key: string): string | null
}

// Web implementation
export class WebStorage extends Storage {
  getItem(key: string) {
    return localStorage.getItem(key)
  }
}

// Node implementation
export class ServerStorage extends Storage {
  getItem(key: string) {
    return process.env[key] ?? null
  }
}

Module Error Handling

Unified error handling mechanism example:

// error.ts module
export class AppError extends Error {
  constructor(
    public readonly code: string,
    message?: string
  ) {
    super(message)
  }
}

export function handleError(error: unknown) {
  if (error instanceof AppError) {
    console.error(`[${error.code}]`, error.message)
  } else {
    console.error('Unknown error', error)
  }
}

Module Lifecycle Management

Modules requiring initialization should provide clear lifecycle methods:

// db.ts module
let connection: DatabaseConnection | null = null

export async function connectDB(config: DBConfig) {
  if (connection) return connection
  connection = await createConnection(config)
  return connection
}

export async function disconnectDB() {
  if (connection) {
    await connection.close()
    connection = null
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:依赖类型管理

下一篇:泛型基础概念

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.