Lesson 06-TypeScript Advanced Application Development

Large-Scale Project Architecture

Monolithic Architecture vs. Micro-Frontend Architecture

TypeScript Practices in Monolithic Architecture:

// Example of Modular Design in a Monolithic Project
src/
├── core/               # Core business logic
├── modules/            # Feature modules
│   ├── user/           # User module
│   ├── product/        # Product module
│   └── order/          # Order module
├── shared/             # Shared utilities and types
│   ├── types/          # Global type definitions
│   └── utils/          # Common utility functions
└── app.ts              # Application entry point
// Example of Inter-Module Communication
// modules/user/types.ts
export interface User {
  id: number
  name: string
}

// modules/order/types.ts
import { User } from '../user/types'

export interface Order {
  id: number
  userId: number
  user?: User // Optional association
}

TypeScript Integration in Micro-Frontend Architecture:

// Main Application Configuration (using Qiankun)
// main-app/src/micro-apps.ts
import { registerMicroApps, start } from 'qiankun'

registerMicroApps([
  {
    name: 'user-app',
    entry: '//localhost:7101',
    container: '#user-container',
    activeRule: '/user',
    props: { 
      sharedTypes: { 
        User: { id: number; name: string } // Shared type definitions
      }
    }
  },
  {
    name: 'product-app',
    entry: '//localhost:7102',
    container: '#product-container',
    activeRule: '/product'
  }
])

start()

// Sub-Application Configuration (using Vite)
// user-app/vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig(({ mode }) => ({
  plugins: [vue()],
  base: mode === 'micro' ? '/user/' : '/',
  define: {
    __MICRO_FRONTEND__: JSON.stringify(true)
  }
}))

Type-Safe Module Boundaries

Module Boundary Design Patterns:

// Shared Type Definitions (Core Boundary)
// shared/types/api.d.ts
export interface ApiResponse<T> {
  code: number
  data: T
  message: string
}

// Strict Module Exports
// modules/user/index.ts
export { User } from './types'
export { fetchUser } from './api'
// Do not expose internal implementation details

// Inter-Module Communication via Well-Defined Interfaces
// modules/order/types.ts
import type { User } from '../user/types'

export interface Order {
  id: number
  user: User // Explicit dependency
}

Dependency Injection for Boundary Control:

// Core Service Container
// core/container.ts
type ServiceMap = {
  userService: UserService
  orderService: OrderService
}

class Container {
  private services: Partial<ServiceMap> = {}

  register<T extends keyof ServiceMap>(key: T, service: ServiceMap[T]) {
    this.services[key] = service
  }

  resolve<T extends keyof ServiceMap>(key: T): ServiceMap[T] {
    if (!this.services[key]) {
      throw new Error(`Service ${String(key)} not registered`)
    }
    return this.services[key]
  }
}

// Modules Access Dependencies via Container
// modules/order/service.ts
class OrderService {
  constructor(private container: Container) {}

  async createOrder(userId: number) {
    const userService = this.container.resolve('userService')
    const user = await userService.getUser(userId)
    // ...
  }
}

Type Specifications for Cross-Team Collaboration

Shared Type Library Design:

// Shared-Types Library Structure
shared-types/
├── src/
│   ├── core/           # Core base types
│   │   ├── entities.ts # Entity definitions
│   │   └── enums.ts    # Enum definitions
│   ├── modules/        # Module-specific types
│   │   ├── user.ts
│   │   └── product.ts
│   └── index.ts        # Unified exports
├── package.json
└── tsconfig.json
// package.json Configuration
{
  "name": "@company/shared-types",
  "version": "1.0.0",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"],
  "publishConfig": {
    "access": "public"
  }
}

// Usage Example (in Other Team Projects)
import { User, UserRole } from '@company/shared-types'

Version Management and Compatibility:

# Semantic Versioning
npm version patch # Fix type bugs
npm version minor # Add backward-compatible types
npm version major # Breaking type changes

# Use Changesets for Managing Changes
npx changeset add
# Select scope of impact and describe changes

Type-Driven Development Workflow

Type-First Development Example:

// 1. Define Types First
interface UserAPI {
  getUser(id: number): Promise<User>
  createUser(data: UserCreateDto): Promise<User>
}

// 2. Implement Service Based on Types
class UserService implements UserAPI {
  async getUser(id: number) {
    // Implementation details
  }
  
  async createUser(data: UserCreateDto) {
    // Implementation details
  }
}

// 3. Type-Driven Component Development
interface UserProps {
  user: User
  onUpdate: (data: Partial<User>) => void
}

const UserComponent: React.FC<UserProps> = ({ user, onUpdate }) => {
  // Component implementation
}

Type Testing Validation:

// Type Testing with TSD
// tests/userTypes.test-d.ts
import { expectType } from 'tsd'
import { User, UserCreateDto } from '../src/modules/user/types'

expectType<User>({
  id: 1,
  name: 'Alice',
  email: 'alice@example.com'
})

expectType<UserCreateDto>({
  name: 'Bob',
  email: 'bob@example.com'
  // age: 30 // Error: Property should not exist
})

Performance Optimization for Large Projects

Compilation Performance Optimization Strategies:

// Optimized tsconfig.json Configuration
{
  "compilerOptions": {
    "incremental": true,
    "composite": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  },
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/utils" }
  ]
}

// Optimized Project Structure
{
  "exclude": [
    "**/node_modules",
    "**/dist",
    "**/*.test.ts",
    "**/*.spec.ts"
  ]
}

Runtime Performance Optimization:

// Type-Safe Performance-Critical Code
// Using Web Worker for CPU-Intensive Tasks
// worker-types.ts
export interface WorkerMessage<T = any> {
  type: string
  payload: T
}

// Main Thread
const worker = new Worker('./worker.ts')
worker.postMessage<WorkerMessage>({
  type: 'PROCESS_DATA',
  payload: largeDataSet
})

// worker.ts
self.onmessage = (e: MessageEvent<WorkerMessage>) => {
  const { type, payload } = e.data
  if (type === 'PROCESS_DATA') {
    const result = heavyProcessing(payload)
    self.postMessage(result)
  }
}
Share your love