TypeScript效能最佳化實戰:從編譯時到執行時的5種生產模式

前端工程

你的TypeScript專案正在慢性死亡

10萬行程式碼的TypeScript專案,tsc一次要45秒,HMR重新整理卡3秒,打包產物2.4MB,線上首屏3.8秒——這不是個例,這是2026年大多數TypeScript專案的真實寫照。型別系統本該是開發效率的倍增器,卻變成了效能殺手。Project References沒人配,skipLibCheck不敢開,泛型巢狀五層,執行時type guard寫在熱路徑上,bundle裡塞滿了沒tree-shake掉的死程式碼。

本文將從核心概念出發,帶你完成型別檢查加速→建構最佳化→執行時效能→記憶體效率→生產監控的5種生產模式,從編譯時到執行時,從開發體驗到線上指標,一步不落。


核心概念

概念 說明
Type Checking Speed TypeScript編譯器對型別進行檢查的速度,受專案結構、型別複雜度、設定影響
Project References 將大型專案拆分為多個子專案,實現增量編譯和並行型別檢查
Incremental Build 利用快取只重新檢查變更部分,避免全量型別檢查
Tree-Shaking 建構工具識別並移除未參考程式碼,減少最終bundle體積
Structural Typing TypeScript的結構化型別系統,透過形狀而非名義進行型別相容判斷
Branded Types 透過唯一標記建立名義型別,在結構型別系統中實現型別隔離
Const Assertions as const斷言,將值推斷為最窄的字面量型別,減少型別空間膨脹
Performance Budget 為bundle大小、編譯時間等設定預算閾值,CI中自動攔截效能退化

最佳化流程

編譯時最佳化:
專案拆分(Project References) → 增量編譯(Incremental) → skipLibCheck → 隔離模組編譯

建構時最佳化:
tsup/esbuild替代tsc → Tree-Shaking → Code Splitting → Bundle壓縮

執行時最佳化:
避免熱路徑type guard → 高效泛型 → 內聯型別斷言 → 減少執行時型別檢查

記憶體最佳化:
結構型別複用 → Branded Types替代類別繼承 → const assertions → 型別收窄

生產監控:
型別覆蓋率 → Bundle分析 → Performance Budget → CI整合

問題分析:TypeScript效能的5大瓶頸

  1. 型別檢查速度慢:單一大專案全量tsc耗時隨程式碼量線性增長,10萬行程式碼專案tsc需30-60秒,CI流水線被型別檢查阻塞
  2. 建構產物臃腫:tsc只做型別檢查不做tree-shaking,barrel exports導致大量死程式碼進入bundle,執行時型別守衛程式碼膨脹
  3. 執行時效能損耗:熱路徑上頻繁的typeof/instanceof檢查,深層泛型實例化產生的執行時開銷,過度使用class裝飾器
  4. 記憶體效率低下:複雜型別推斷佔用大量編譯器記憶體,執行時大量相似結構型別建立重複物件,未使用const assertion導致型別空間膨脹
  5. 缺乏效能監控:沒有型別覆蓋率指標,bundle大小無預算控制,編譯時間退化無感知,線上效能問題無法回溯到型別設計

分步實操:5種生產模式

模式1:型別檢查速度最佳化

// tsconfig.base.json - 基礎設定
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "skipLibCheck": true,
    "incremental": true,
    "tsBuildInfoFile": ".tsbuildinfo",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true
  }
}

// packages/core/tsconfig.json - 核心套件設定
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"],
  "references": [
    { "path": "../shared" }
  ]
}

// packages/shared/tsconfig.json - 共享套件設定
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"]
}

// packages/app/tsconfig.json - 應用套件設定
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src",
    "noEmit": true
  },
  "include": ["src"],
  "references": [
    { "path": "../core" },
    { "path": "../shared" }
  ]
}

// tsconfig.json - 頂層解決方案設定
{
  "files": [],
  "references": [
    { "path": "packages/shared" },
    { "path": "packages/core" },
    { "path": "packages/app" }
  ]
}
// scripts/typecheck.ts - 增量型別檢查指令碼
import { execSync } from 'child_process';
import { readFileSync, existsSync, unlinkSync } from 'fs';
import { performance } from 'perf_hooks';

interface TypeCheckResult {
  project: string;
  duration: number;
  errors: number;
  cached: boolean;
}

function typecheckProject(projectPath: string, clean: boolean = false): TypeCheckResult {
  const buildInfoFile = `${projectPath}/.tsbuildinfo`;
  const wasCached = existsSync(buildInfoFile) && !clean;

  if (clean && existsSync(buildInfoFile)) {
    unlinkSync(buildInfoFile);
  }

  const start = performance.now();
  let errors = 0;

  try {
    execSync(`npx tsc --build ${projectPath} --verbose`, {
      encoding: 'utf-8',
      stdio: 'pipe',
    });
  } catch (error: any) {
    const output = error.stdout || error.stderr || '';
    const errorMatches = output.match(/error TS\d+:/g);
    errors = errorMatches ? errorMatches.length : 0;
  }

  const duration = performance.now() - start;

  return {
    project: projectPath,
    duration: Math.round(duration),
    errors,
    cached: wasCached,
  };
}

function runFullTypeCheck(clean: boolean = false): void {
  const projects = [
    'packages/shared',
    'packages/core',
    'packages/app',
  ];

  console.log('=== TypeScript 型別檢查報告 ===\n');

  let totalDuration = 0;
  let totalErrors = 0;

  for (const project of projects) {
    const result = typecheckProject(project, clean);
    totalDuration += result.duration;
    totalErrors += result.errors;

    const status = result.errors === 0 ? '✓' : '✗';
    const cacheStatus = result.cached ? '(cached)' : '(full)';
    console.log(
      `${status} ${result.project}: ${result.duration}ms ${cacheStatus}, ${result.errors} errors`
    );
  }

  console.log(`\n總計: ${totalDuration}ms, ${totalErrors} errors`);

  if (totalDuration > 10000) {
    console.warn('\n⚠️  型別檢查超過10秒預算!建議:');
    console.warn('  - 新增更多Project References');
    console.warn('  - 啟用skipLibCheck');
    console.warn('  - 使用isolatedModules');
  }
}

const isClean = process.argv.includes('--clean');
runFullTypeCheck(isClean);
// src/types/performance-optimized.ts - 最佳化型別定義減少檢查負擔

// ❌ 複雜的條件型別導致型別檢查緩慢
type DeepPartial<T> = T extends object
  ? { [K in keyof T]?: DeepPartial<T[K]> }
  : T;

type DeepRequired<T> = T extends object
  ? { [K in keyof T]-?: DeepRequired<T[K]> }
  : T;

// ✅ 使用內建工具型別,避免重複實例化
type CachedPartial<T> = Partial<T>;
type CachedRequired<T> = Required<T>;

// ❌ 遞迴型別深度過大
type FlattenDeep<T> = T extends Array<infer U>
  ? FlattenDeep<U>
  : T;

// ✅ 限制遞迴深度
type FlattenN<T, N extends number, D extends any[] = []> =
  D['length'] extends N
    ? T
    : T extends Array<infer U>
      ? FlattenN<U, N, [...D, 1]>
      : T;

type Flatten3<T> = FlattenN<T, 3>;

// ❌ 過度使用模板字面量型別
type Route = `/api/${string}/${string}`;

// ✅ 使用聯合型別替代模板字面量
type ApiRoute =
  | '/api/users'
  | '/api/users/:id'
  | '/api/posts'
  | '/api/posts/:id'
  | '/api/comments'
  | '/api/comments/:id';

// ❌ 大型聯合型別
type Status = 'pending' | 'processing' | 'approved' | 'rejected' | 'cancelled' | 'refunded' | 'completed' | 'archived' | 'draft' | 'published';

// ✅ 分組聯合型別
type OrderStatus = 'pending' | 'processing' | 'completed' | 'cancelled';
type ContentStatus = 'draft' | 'published' | 'archived';
type PaymentStatus = 'approved' | 'rejected' | 'refunded';

// skipLibCheck最佳化的.d.ts
declare module 'heavy-lib' {
  export interface HeavyConfig {
    readonly apiKey: string;
    readonly endpoint: string;
    readonly timeout: number;
    readonly retries: number;
  }

  export function createClient(config: HeavyConfig): HeavyClient;

  export interface HeavyClient {
    getData<T>(id: string): Promise<T>;
    setData<T>(id: string, data: T): Promise<void>;
  }
}

模式2:建構最佳化與tsup/esbuild

// tsup.config.ts - tsup建構設定
import { defineConfig } from 'tsup';

export default defineConfig([
  {
    entry: ['src/index.ts'],
    format: ['esm', 'cjs'],
    dts: {
      resolve: true,
      compilerOptions: {
        skipLibCheck: true,
        composite: false,
      },
    },
    splitting: true,
    treeshake: true,
    minify: true,
    sourcemap: true,
    clean: true,
    outDir: 'dist',
    target: 'es2022',
    platform: 'node',
    external: ['react', 'react-dom'],
    esbuildOptions(options) {
      options.logLevel = 'info';
      options.chunkNames = 'chunks/[name]-[hash]';
    },
  },
  {
    entry: ['src/browser.ts'],
    format: ['esm'],
    treeshake: true,
    minify: true,
    sourcemap: true,
    outDir: 'dist/browser',
    target: 'es2022',
    platform: 'browser',
    esbuildOptions(options) {
      options.conditions = ['browser'];
    },
  },
]);
// src/index.ts - 最佳化匯出結構以支援tree-shaking

// ❌ barrel export導致tree-shaking失效
// export * from './utils';
// export * from './validators';
// export * from './transformers';

// ✅ 明確命名匯出,便於bundler分析依賴
export { validateEmail, validateUrl } from './validators/email';
export { validateAge, validateRange } from './validators/number';
export { formatDate, parseDate } from './transformers/date';
export { formatCurrency, parseCurrency } from './transformers/currency';

// ✅ 使用條件匯出減少瀏覽器bundle
export type { UserSchema, CreateUserInput } from './types/user';
export type { PaginationParams, SearchParams } from './types/pagination';
// scripts/bundle-analysis.ts - Bundle分析指令碼
import { build } from 'esbuild';
import { readFileSync, writeFileSync } from 'fs';
import { gzipSync } from 'zlib';

interface BundleMetrics {
  name: string;
  size: number;
  gzipSize: number;
  modules: number;
}

const BUDGET = {
  maxBundleSize: 100 * 1024,
  maxGzipSize: 30 * 1024,
  maxChunkSize: 50 * 1024,
};

async function analyzeBundle(entryPoint: string): Promise<BundleMetrics> {
  const result = await build({
    entryPoints: [entryPoint],
    bundle: true,
    minify: true,
    write: false,
    metafile: true,
    format: 'esm',
    target: 'es2022',
    external: ['react', 'react-dom'],
  });

  const outputFiles = result.outputFiles || [];
  const metafile = result.metafile;

  let totalSize = 0;
  for (const file of outputFiles) {
    totalSize += file.contents.byteLength;
  }

  const gzipSize = gzipSync(Buffer.from(outputFiles[0]?.contents || [])).byteLength;

  const moduleCount = metafile ? Object.keys(metafile.inputs).length : 0;

  return {
    name: entryPoint,
    size: totalSize,
    gzipSize,
    modules: moduleCount,
  };
}

async function runBundleAnalysis(): Promise<void> {
  console.log('=== Bundle 分析報告 ===\n');

  const entryPoints = [
    'src/index.ts',
    'src/browser.ts',
  ];

  let hasViolation = false;

  for (const entry of entryPoints) {
    const metrics = await analyzeBundle(entry);

    const sizeKB = (metrics.size / 1024).toFixed(1);
    const gzipKB = (metrics.gzipSize / 1024).toFixed(1);

    console.log(`${entry}:`);
    console.log(`  大小: ${sizeKB}KB (預算: ${BUDGET.maxBundleSize / 1024}KB)`);
    console.log(`  Gzip: ${gzipKB}KB (預算: ${BUDGET.maxGzipSize / 1024}KB)`);
    console.log(`  模組: ${metrics.modules}`);

    if (metrics.size > BUDGET.maxBundleSize) {
      console.warn(`  ⚠️  Bundle大小超過預算!`);
      hasViolation = true;
    }

    if (metrics.gzipSize > BUDGET.maxGzipSize) {
      console.warn(`  ⚠️  Gzip大小超過預算!`);
      hasViolation = true;
    }

    console.log();
  }

  if (hasViolation) {
    console.error('❌ 效能預算違規!');
    process.exit(1);
  } else {
    console.log('✅ 所有bundle都在預算內。');
  }
}

runBundleAnalysis();
// package.json - 建構指令碼最佳化
{
  "scripts": {
    "typecheck": "tsc --build",
    "typecheck:clean": "tsc --build --clean && tsc --build",
    "build": "tsup",
    "build:analyze": "tsup --metafile && node scripts/bundle-analysis.ts",
    "dev": "tsup --watch",
    "check:all": "npm run typecheck && npm run build && npm run test",
    "prepack": "npm run build"
  }
}

模式3:執行時效能最佳化

// src/runtime/hot-path.ts - 熱路徑型別守衛最佳化

// ❌ 在熱路徑上使用複雜型別守衛
function processData(data: unknown): ProcessedData {
  if (
    typeof data === 'object' &&
    data !== null &&
    'id' in data &&
    typeof (data as any).id === 'string' &&
    'name' in data &&
    typeof (data as any).name === 'string' &&
    'age' in data &&
    typeof (data as any).age === 'number' &&
    'email' in data &&
    typeof (data as any).email === 'string'
  ) {
    return data as ProcessedData;
  }
  throw new Error('Invalid data');
}

// ✅ 最小化型別守衛,信任編譯時型別
interface ProcessedData {
  id: string;
  name: string;
  age: number;
  email: string;
}

function processDataOptimized(data: unknown): ProcessedData {
  if (typeof data !== 'object' || data === null) {
    throw new Error('Expected object');
  }
  return data as ProcessedData;
}

// ✅ 分層校驗:熱路徑快速檢查,冷路徑嚴格校驗
function processHotPath(data: unknown): ProcessedData {
  if (typeof data !== 'object' || data === null) {
    throw new Error('Expected object');
  }
  return data as ProcessedData;
}

function processColdPath(data: unknown): ProcessedData {
  const result = ProcessedDataSchema.safeParse(data);
  if (!result.success) {
    throw new Error(`校驗失敗: ${result.error.message}`);
  }
  return result.data;
}

import { z } from 'zod';

const ProcessedDataSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1),
  age: z.number().int().min(0),
  email: z.string().email(),
});
// src/runtime/generics.ts - 高效泛型模式

// ❌ 泛型實例化導致執行時膨脹
class DataStore<T> {
  private items: T[] = [];

  add(item: T): void {
    this.items.push(item);
  }

  get(index: number): T | undefined {
    return this.items[index];
  }

  filter(predicate: (item: T) => boolean): T[] {
    return this.items.filter(predicate);
  }

  map<U>(transform: (item: T) => U): U[] {
    return this.items.map(transform);
  }

  reduce<U>(reducer: (acc: U, item: T) => U, initial: U): U {
    return this.items.reduce(reducer, initial);
  }
}

// ✅ 使用函數式工具替代泛型類別
interface DataStore {
  readonly items: readonly unknown[];
}

function createStore<T>(initialItems: T[] = []): DataStore {
  return { items: Object.freeze([...initialItems]) };
}

function addItem<T>(store: DataStore, item: T): DataStore {
  return { items: Object.freeze([...store.items, item]) };
}

function getItem<T>(store: DataStore, index: number): T {
  return store.items[index] as T;
}

function filterItems<T>(store: DataStore, predicate: (item: T) => boolean): T[] {
  return store.items.filter(predicate as (item: unknown) => boolean) as T[];
}

// ✅ 使用條件型別替代執行時分支
type Result<T, E = Error> =
  | { readonly ok: true; readonly value: T }
  | { readonly ok: false; readonly error: E };

function ok<T>(value: T): Result<T> {
  return { ok: true, value };
}

function err<E>(error: E): Result<never, E> {
  return { ok: false, error };
}

function mapResult<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {
  return result.ok ? ok(fn(result.value)) : result;
}

function flatMapResult<T, U, E>(
  result: Result<T, E>,
  fn: (value: T) => Result<U, E>
): Result<U, E> {
  return result.ok ? fn(result.value) : result;
}

// ✅ 避免執行時型別抹除的開銷
interface TypeTag<T extends string> {
  readonly __type: T;
}

type UserId = string & TypeTag<'UserId'>;
type OrderId = string & TypeTag<'OrderId'>;

function createUserId(id: string): UserId {
  return id as UserId;
}

function createOrderId(id: string): OrderId {
  return id as OrderId;
}

function getUser(id: UserId): Promise<User | null> {
  return Promise.resolve(null);
}

function getOrder(id: OrderId): Promise<Order | null> {
  return Promise.resolve(null);
}

interface User {
  id: UserId;
  name: string;
}

interface Order {
  id: OrderId;
  total: number;
}
// src/runtime/iteration.ts - 高效迭代模式

// ❌ 每次迭代建立新陣列
function processUsers(users: User[]): ProcessedUser[] {
  return users
    .filter((u) => u.age >= 18)
    .map((u) => ({ ...u, displayName: u.name.toUpperCase() }))
    .filter((u) => u.displayName.length > 0)
    .map((u) => ({ ...u, score: calculateScore(u) }));
}

// ✅ 單次遍歷替代多次鏈式呼叫
function processUsersOptimized(users: User[]): ProcessedUser[] {
  const result: ProcessedUser[] = [];

  for (const u of users) {
    if (u.age < 18) continue;

    const displayName = u.name.toUpperCase();
    if (displayName.length === 0) continue;

    result.push({
      ...u,
      displayName,
      score: calculateScore(u),
    });
  }

  return result;
}

// ✅ 使用生成器延遲計算
function* filterUsers(users: Iterable<User>): Generator<User> {
  for (const u of users) {
    if (u.age >= 18) yield u;
  }
}

function* mapUsers(users: Iterable<User>): Generator<ProcessedUser> {
  for (const u of users) {
    yield {
      ...u,
      displayName: u.name.toUpperCase(),
      score: calculateScore(u),
    };
  }
}

function processUsersLazy(users: User[]): ProcessedUser[] {
  return [...mapUsers(filterUsers(users))];
}

interface ProcessedUser extends User {
  displayName: string;
  score: number;
}

function calculateScore(user: User): number {
  return user.name.length * user.age;
}

模式4:記憶體效率最佳化

// src/memory/structural-typing.ts - 結構型別複用

// ❌ 每個介面獨立定義,編譯器為每個建立獨立型別
interface UserResponse {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'editor' | 'viewer';
  createdAt: string;
}

interface UserListItem {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'editor' | 'viewer';
  createdAt: string;
}

interface UserProfile {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'editor' | 'viewer';
  createdAt: string;
  bio: string;
  avatar: string;
}

// ✅ 使用基礎型別+組合複用
interface BaseEntity {
  readonly id: string;
  readonly createdAt: string;
  readonly updatedAt: string;
}

type UserRole = 'admin' | 'editor' | 'viewer';

interface UserBase extends BaseEntity {
  readonly name: string;
  readonly email: string;
  readonly role: UserRole;
}

type UserResponse = UserBase;
type UserListItem = UserBase;

interface UserProfile extends UserBase {
  readonly bio: string;
  readonly avatar: string;
}

// ✅ 使用Pick/Omit從基礎型別派生
type UserSummary = Pick<UserBase, 'id' | 'name' | 'role'>;
type UserEmailInfo = Pick<UserBase, 'id' | 'email'>;
type UserWithoutRole = Omit<UserBase, 'role'>;
// src/memory/branded-types.ts - Branded Types替代類別繼承

// ❌ 使用類別繼承導致執行時原型鏈開銷
class Entity {
  constructor(
    public id: string,
    public createdAt: Date,
  ) {}
}

class UserEntity extends Entity {
  constructor(
    id: string,
    createdAt: Date,
    public name: string,
    public email: string,
  ) {
    super(id, createdAt);
  }
}

class OrderEntity extends Entity {
  constructor(
    id: string,
    createdAt: Date,
    public total: number,
    public status: string,
  ) {
    super(id, createdAt);
  }
}

// ✅ 使用Branded Types + 純資料物件
interface Brand<T extends string> {
  readonly __brand: T;
}

type Branded<T, B extends string> = T & Brand<B>;

type UserId = Branded<string, 'UserId'>;
type OrderId = Branded<string, 'OrderId'>;
type ProductId = Branded<string, 'ProductId'>;

function createUserId(id: string): UserId {
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(id)) {
    throw new Error('UserId的UUID格式無效');
  }
  return id as UserId;
}

function createOrderId(id: string): OrderId {
  if (!/^ORD-\d{8}$/.test(id)) {
    throw new Error('訂單ID格式無效');
  }
  return id as OrderId;
}

interface User {
  readonly id: UserId;
  readonly name: string;
  readonly email: string;
  readonly role: UserRole;
}

interface Order {
  readonly id: OrderId;
  readonly userId: UserId;
  readonly total: number;
  readonly status: OrderStatus;
  readonly items: ReadonlyArray<OrderItem>;
}

type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';

interface OrderItem {
  readonly productId: ProductId;
  readonly quantity: number;
  readonly unitPrice: number;
}

// ✅ Branded Types確保型別安全,零執行時開銷
function getUserOrders(userId: UserId, orders: ReadonlyArray<Order>): ReadonlyArray<Order> {
  return orders.filter((o) => o.userId === userId);
}

// 編譯時防止ID混用
// getUserOrders(createOrderId('ORD-20260616'), orders); // ❌ 型別錯誤
// src/memory/const-assertions.ts - const assertions最佳化

// ❌ 寬泛型別導致編譯器建立大量型別實例
const ROUTES = {
  users: '/api/users',
  posts: '/api/posts',
  comments: '/api/comments',
};

type RouteKey = keyof typeof ROUTES; // string
type RouteValue = typeof ROUTES[keyof typeof ROUTES]; // string

// ✅ const assertion鎖定字面量型別
const ROUTES = {
  users: '/api/users',
  posts: '/api/posts',
  comments: '/api/comments',
} as const;

type RouteKey = keyof typeof ROUTES; // 'users' | 'posts' | 'comments'
type RouteValue = typeof ROUTES[keyof typeof ROUTES]; // '/api/users' | '/api/posts' | '/api/comments'

// ✅ const assertion + satisfies模式
const HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as const;
type HttpMethod = typeof HTTP_METHODS[number]; // 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'

const STATUS_CODES = {
  OK: 200,
  CREATED: 201,
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  INTERNAL_ERROR: 500,
} as const;

type StatusCode = typeof STATUS_CODES[keyof typeof STATUS_CODES];
// 200 | 201 | 400 | 401 | 403 | 404 | 500

// ✅ 使用satisfies確保型別正確同時保留字面量型別
const API_CONFIG = {
  baseUrl: 'https://api.example.com',
  timeout: 5000,
  retries: 3,
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
} as const satisfies Record<string, string | number | Record<string, string>>;

type ApiConfigKey = keyof typeof API_CONFIG; // 'baseUrl' | 'timeout' | 'retries' | 'headers'

// ✅ 凍結物件防止執行時修改
const IMMUTABLE_CONFIG = Object.freeze({
  MAX_RETRIES: 3,
  TIMEOUT_MS: 5000,
  PAGE_SIZE: 20,
  MAX_PAGE_SIZE: 100,
} as const);

type Config = typeof IMMUTABLE_CONFIG;
// src/memory/type-narrowing.ts - 高效型別收窄

// ❌ 多次重複型別守衛
function handleData(data: unknown): string {
  if (typeof data === 'object' && data !== null && 'type' in data) {
    if ((data as any).type === 'user') {
      if (typeof (data as any).name === 'string') {
        return (data as any).name;
      }
    }
    if ((data as any).type === 'order') {
      if (typeof (data as any).id === 'string') {
        return (data as any).id;
      }
    }
  }
  return 'unknown';
}

// ✅ 使用判別聯合 + 型別守衛函式
interface UserData {
  readonly type: 'user';
  readonly name: string;
  readonly email: string;
}

interface OrderData {
  readonly type: 'order';
  readonly id: string;
  readonly total: number;
}

type AppData = UserData | OrderData;

function isUserData(data: AppData): data is UserData {
  return data.type === 'user';
}

function isOrderData(data: AppData): data is OrderData {
  return data.type === 'order';
}

function handleDataOptimized(data: AppData): string {
  switch (data.type) {
    case 'user':
      return data.name;
    case 'order':
      return data.id;
  }
}

// ✅ 使用型別謂詞快取
type TypeGuard<T> = (value: unknown) => value is T;

function createTypeGuard<T>(check: (value: unknown) => boolean): TypeGuard<T> {
  return (value: unknown): value is T => check(value);
}

const isString = createTypeGuard<string>((v) => typeof v === 'string');
const isNumber = createTypeGuard<number>((v) => typeof v === 'number');
const isBoolean = createTypeGuard<boolean>((v) => typeof v === 'boolean');

function parseEnvValue<T>(
  value: string | undefined,
  guard: TypeGuard<T>,
  defaultValue: T,
): T {
  if (value === undefined) return defaultValue;
  const parsed: unknown = value;
  return guard(parsed) ? parsed : defaultValue;
}

const port = parseEnvValue(process.env.PORT, isNumber, 3000);
const debug = parseEnvValue(process.env.DEBUG, isBoolean, false);

模式5:生產監控與效能預算

// scripts/type-coverage.ts - 型別覆蓋率檢查
import { execSync } from 'child_process';

interface TypeCoverageResult {
  totalFiles: number;
  typedFiles: number;
  coverage: number;
  anyCount: number;
  unsafeCount: number;
}

function checkTypeCoverage(): TypeCoverageResult {
  try {
    const output = execSync(
      'npx type-coverage --detail --at-least 95',
      { encoding: 'utf-8', stdio: 'pipe' }
    );

    const match = output.match(/(\d+)\/(\d+) files/);
    const anyMatch = output.match(/(\d+) any/);

    const typedFiles = match ? parseInt(match[1], 10) : 0;
    const totalFiles = match ? parseInt(match[2], 10) : 0;
    const anyCount = anyMatch ? parseInt(anyMatch[1], 10) : 0;

    return {
      totalFiles,
      typedFiles,
      coverage: totalFiles > 0 ? (typedFiles / totalFiles) * 100 : 0,
      anyCount,
      unsafeCount: anyCount,
    };
  } catch {
    return {
      totalFiles: 0,
      typedFiles: 0,
      coverage: 0,
      anyCount: -1,
      unsafeCount: -1,
    };
  }
}

function reportTypeCoverage(): void {
  const result = checkTypeCoverage();

  console.log('=== 型別覆蓋率報告 ===\n');
  console.log(`檔案: ${result.typedFiles}/${result.totalFiles}`);
  console.log(`覆蓋率: ${result.coverage.toFixed(1)}%`);
  console.log(`any數量: ${result.anyCount}`);

  if (result.coverage < 95) {
    console.warn('\n⚠️  型別覆蓋率低於95%!');
    console.warn('  執行 `npx type-coverage --detail` 找出無型別程式碼。');
  }

  if (result.coverage < 80) {
    console.error('❌ 型別覆蓋率嚴重不足!');
    process.exit(1);
  }
}

reportTypeCoverage();
// scripts/performance-budget.ts - 效能預算CI檢查
import { readFileSync } from 'fs';
import { gzipSync } from 'zlib';

interface PerformanceBudget {
  maxBundleSize: number;
  maxGzipSize: number;
  maxTypeCheckTime: number;
  minTypeCoverage: number;
  maxChunkCount: number;
}

const DEFAULT_BUDGET: PerformanceBudget = {
  maxBundleSize: 100 * 1024,       // 100KB
  maxGzipSize: 30 * 1024,          // 30KB
  maxTypeCheckTime: 15000,         // 15s
  minTypeCoverage: 95,             // 95%
  maxChunkCount: 10,
};

interface BudgetCheckResult {
  metric: string;
  value: number;
  budget: number;
  unit: string;
  passed: boolean;
}

function checkBundleBudget(
  bundlePath: string,
  budget: PerformanceBudget = DEFAULT_BUDGET,
): BudgetCheckResult[] {
  const results: BudgetCheckResult[] = [];

  try {
    const content = readFileSync(bundlePath);
    const size = content.byteLength;
    const gzipSize = gzipSync(content).byteLength;

    results.push({
      metric: 'Bundle大小',
      value: size,
      budget: budget.maxBundleSize,
      unit: 'bytes',
      passed: size <= budget.maxBundleSize,
    });

    results.push({
      metric: 'Gzip大小',
      value: gzipSize,
      budget: budget.maxGzipSize,
      unit: 'bytes',
      passed: gzipSize <= budget.maxGzipSize,
    });
  } catch {
    results.push({
      metric: 'Bundle大小',
      value: -1,
      budget: budget.maxBundleSize,
      unit: 'bytes',
      passed: false,
    });
  }

  return results;
}

function checkTypeCheckBudget(
  budget: PerformanceBudget = DEFAULT_BUDGET,
): BudgetCheckResult {
  const start = Date.now();
  try {
    execSync('npx tsc --noEmit', { encoding: 'utf-8', stdio: 'pipe' });
  } catch {
    // 型別錯誤另行處理
  }
  const duration = Date.now() - start;

  return {
    metric: '型別檢查時間',
    value: duration,
    budget: budget.maxTypeCheckTime,
    unit: 'ms',
    passed: duration <= budget.maxTypeCheckTime,
  };
}

function runPerformanceBudget(): void {
  console.log('=== 效能預算檢查 ===\n');

  const results: BudgetCheckResult[] = [
    ...checkBundleBudget('dist/index.js'),
    checkTypeCheckBudget(),
  ];

  let allPassed = true;

  for (const result of results) {
    const status = result.passed ? '✓' : '✗';
    const valueStr = result.value >= 0
      ? result.unit === 'bytes'
        ? `${(result.value / 1024).toFixed(1)}KB`
        : `${result.value}${result.unit}`
      : 'N/A';
    const budgetStr = result.unit === 'bytes'
      ? `${(result.budget / 1024).toFixed(1)}KB`
      : `${result.budget}${result.unit}`;

    console.log(`${status} ${result.metric}: ${valueStr} (預算: ${budgetStr})`);

    if (!result.passed) {
      allPassed = false;
    }
  }

  if (!allPassed) {
    console.error('\n❌ 效能預算違規!');
    process.exit(1);
  } else {
    console.log('\n✅ 所有效能預算達標。');
  }
}

import { execSync } from 'child_process';
runPerformanceBudget();
// .github/workflows/typescript-perf.yml - CI效能監控
// GitHub Actions工作流程設定
/*
name: TypeScript Performance

on:
  pull_request:
    paths:
      - '**.ts'
      - '**.tsx'
      - 'tsconfig*.json'
      - 'package.json'

jobs:
  performance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - run: npm ci
      - name: Type Check
        run: |
          START=$(date +%s%N)
          npx tsc --noEmit
          END=$(date +%s%N)
          DURATION=$(( (END - START) / 1000000 ))
          echo "Type check duration: ${DURATION}ms"
          if [ $DURATION -gt 15000 ]; then
            echo "::error::型別檢查超過15秒預算 (${DURATION}ms)"
            exit 1
          fi

      - name: Type Coverage
        run: |
          npx type-coverage --at-least 95 || {
            echo "::error::型別覆蓋率低於95%"
            exit 1
          }

      - name: Bundle Analysis
        run: |
          npm run build
          node scripts/performance-budget.ts

      - name: Comment PR
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const report = fs.readFileSync('perf-report.txt', 'utf8');
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## 📊 TypeScript效能報告\n${report}`
            });
*/
// src/monitoring/runtime-metrics.ts - 執行時效能指標收集
interface PerformanceMetric {
  name: string;
  value: number;
  timestamp: number;
  tags: Record<string, string>;
}

class PerformanceCollector {
  private metrics: PerformanceMetric[] = [];
  private readonly maxMetrics = 1000;

  recordMetric(name: string, value: number, tags: Record<string, string> = {}): void {
    this.metrics.push({
      name,
      value,
      timestamp: Date.now(),
      tags,
    });

    if (this.metrics.length > this.maxMetrics) {
      this.metrics = this.metrics.slice(-this.maxMetrics);
    }
  }

  timeAsync<T>(name: string, fn: () => Promise<T>, tags?: Record<string, string>): Promise<T> {
    const start = performance.now();
    return fn().finally(() => {
      const duration = performance.now() - start;
      this.recordMetric(name, duration, { ...tags, unit: 'ms' });
    });
  }

  timeSync<T>(name: string, fn: () => T, tags?: Record<string, string>): T {
    const start = performance.now();
    try {
      return fn();
    } finally {
      const duration = performance.now() - start;
      this.recordMetric(name, duration, { ...tags, unit: 'ms' });
    }
  }

  getMetrics(name?: string): PerformanceMetric[] {
    if (name) {
      return this.metrics.filter((m) => m.name === name);
    }
    return [...this.metrics];
  }

  getAverage(name: string): number {
    const named = this.getMetrics(name);
    if (named.length === 0) return 0;
    return named.reduce((sum, m) => sum + m.value, 0) / named.length;
  }

  getP95(name: string): number {
    const named = this.getMetrics(name);
    if (named.length === 0) return 0;
    const sorted = named.map((m) => m.value).sort((a, b) => a - b);
    const index = Math.ceil(sorted.length * 0.95) - 1;
    return sorted[index];
  }

  generateReport(): string {
    const metricNames = [...new Set(this.metrics.map((m) => m.name))];
    const lines: string[] = ['### 執行時效能報告\n'];

    for (const name of metricNames) {
      const avg = this.getAverage(name).toFixed(2);
      const p95 = this.getP95(name).toFixed(2);
      const count = this.getMetrics(name).length;
      lines.push(`- **${name}**: avg=${avg}ms, p95=${p95}ms, n=${count}`);
    }

    return lines.join('\n');
  }
}

const perfCollector = new PerformanceCollector();

async function fetchWithMetrics<T>(
  url: string,
  schema: z.ZodSchema<T>,
): Promise<T> {
  return perfCollector.timeAsync(
    'api.fetch',
    async () => {
      const response = await fetch(url);
      const raw = await response.json();
      const result = schema.safeParse(raw);
      if (!result.success) {
        throw new Error(`API校驗失敗: ${result.error.message}`);
      }
      return result.data;
    },
    { url: new URL(url).pathname },
  );
}

常見陷阱

陷阱1:skipLibCheck導致型別不安全

// ❌ 全域skipLibCheck關閉了所有.d.ts檢查
// tsconfig.json
{
  "compilerOptions": {
    "skipLibCheck": true  // 關閉所有函式庫型別檢查
  }
}

// ✅ skipLibCheck只跳過node_modules中的.d.ts,自己的.d.ts仍需檢查
// tsconfig.json
{
  "compilerOptions": {
    "skipLibCheck": true  // 安全:只影響node_modules
  }
}
// 自己的types目錄單獨設定strict檢查
// types/tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "skipLibCheck": false
  }
}

陷阱2:barrel exports破壞tree-shaking

// ❌ index.ts中re-export所有模組
// src/index.ts
export * from './users';
export * from './orders';
export * from './products';
export * from './analytics';

// ✅ 明確按需匯出
// src/index.ts
export { UserService } from './users/service';
export { OrderService } from './orders/service';
export type { User, CreateUserInput } from './users/types';
export type { Order, CreateOrderInput } from './orders/types';

// ✅ package.json中設定sideEffects
// package.json
{
  "sideEffects": false,
  "module": "./dist/index.mjs",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    },
    "./users": {
      "import": "./dist/users.mjs"
    }
  }
}

陷阱3:Project References設定不完整

// ❌ 缺少composite選項導致參照失效
// packages/shared/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist"
    // 缺少 "composite": true
  }
}

// ✅ 被參照的專案必須啟用composite
// packages/shared/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src"]
}

陷阱4:執行時過度使用型別守衛

// ❌ 每次迴圈都做完整型別檢查
function processItems(items: unknown[]): Result[] {
  return items.map((item) => {
    const validated = ItemSchema.parse(item);  // 每次都完整校驗
    return transform(validated);
  });
}

// ✅ 入口校驗一次,內部信任型別
function processItems(items: unknown[]): Result[] {
  const validated = z.array(ItemSchema).parse(items);  // 一次性校驗
  return validated.map(transform);
}

// ✅ 或使用分層校驗
function processItems(items: unknown[]): Result[] {
  return items.map((item) => {
    if (!isPlainObject(item)) throw new Error('Invalid item');
    return transform(item as Item);
  });
}

function isPlainObject(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

陷阱5:忽略編譯器記憶體限制

// ❌ 大型專案預設1.5GB記憶體不夠
// 執行tsc時記憶體溢位
// FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

// ✅ 增加Node.js記憶體限制
// package.json
{
  "scripts": {
    "typecheck": "NODE_OPTIONS='--max-old-space-size=4096' tsc --build",
    "typecheck:ci": "NODE_OPTIONS='--max-old-space-size=8192' tsc --build"
  }
}

// ✅ 拆分專案減少單個編譯器記憶體需求
// 使用Project References將大專案拆分為多個子專案
// 每個子專案獨立編譯,記憶體峰值大幅降低

錯誤排查表

錯誤現象 可能原因 解決方案
tsc超過30秒 單一大專案無Project References 拆分為多個子專案,啟用增量編譯
error TS6307 Project References缺少composite 被參照專案新增"composite": true
bundle體積異常大 barrel exports破壞tree-shaking 改為明確命名匯出,設定sideEffects
HMR重新整理慢 tsc全量重新檢查 啟用incrementalisolatedModules
FATAL ERROR: Reached heap limit 編譯器記憶體溢位 增加--max-old-space-size或拆分專案
型別推斷逾時 遞迴型別深度過大 限制遞迴深度,使用FlattenN<T, 3>
Type instantiation is excessively deep 條件型別巢狀過深 簡化型別邏輯,使用中間型別別名
執行時效能差 熱路徑頻繁型別守衛 分層校驗,熱路徑最小化檢查
skipLibCheck後型別錯誤 自訂.d.ts有問題 自訂types目錄單獨strict檢查
bundle中包含未使用程式碼 tsconfig importsNotUsedAsValues 使用tsup/esbuild替代tsc打包

進階最佳化

編譯器效能調校

// tsconfig.perf.json - 極致效能設定
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": "./.tsbuildinfo",
    "skipLibCheck": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
    "assumeChangesOnlyAffectDirectDependencies": true,
    "disableSourceOfProjectReferenceRedirect": true,
    "disableReferencedProjectLoad": true
  }
}

// scripts/tsc-watch.ts - 智慧增量監聽
import { watch } from 'chokidar';
import { execSync } from 'child_process';
import { relative, dirname, extname } from 'path';
import { performance } from 'perf_hooks';

interface WatchConfig {
  include: string[];
  exclude: string[];
  debounceMs: number;
  projects: Record<string, string[]>;
}

const watchConfig: WatchConfig = {
  include: ['src/**/*.ts'],
  exclude: ['src/**/*.test.ts', 'src/**/*.spec.ts'],
  debounceMs: 300,
  projects: {
    'packages/shared': ['packages/shared/src/**/*.ts'],
    'packages/core': ['packages/core/src/**/*.ts'],
    'packages/app': ['packages/app/src/**/*.ts'],
  },
};

let debounceTimer: NodeJS.Timeout | null = null;

function getAffectedProject(filePath: string): string | null {
  for (const [project, patterns] of Object.entries(watchConfig.projects)) {
    for (const pattern of patterns) {
      const dir = pattern.replace('/**/*.ts', '');
      if (filePath.startsWith(dir)) {
        return project;
      }
    }
  }
  return null;
}

function typecheckAffected(filePath: string): void {
  const project = getAffectedProject(filePath);
  if (!project) return;

  const start = performance.now();
  try {
    execSync(`npx tsc --build ${project}`, { encoding: 'utf-8', stdio: 'pipe' });
    const duration = (performance.now() - start).toFixed(0);
    console.log(`✓ ${project}: ${duration}ms`);
  } catch (error: any) {
    const duration = (performance.now() - start).toFixed(0);
    console.error(`✗ ${project}: ${duration}ms`);
    console.error(error.stdout || error.message);
  }
}

const watcher = watch(watchConfig.include, {
  ignored: watchConfig.exclude,
  persistent: true,
  ignoreInitial: true,
});

watcher.on('change', (filePath) => {
  if (debounceTimer) clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    typecheckAffected(filePath);
  }, watchConfig.debounceMs);
});

watcher.on('add', (filePath) => {
  typecheckAffected(filePath);
});

console.log('🔍 監聽TypeScript變更...');

Bundle最佳化策略

// scripts/advanced-bundle-opt.ts - 進階bundle最佳化
import { build, Plugin } from 'esbuild';

const sizeLimitPlugin: Plugin = {
  name: 'size-limit',
  setup(build) {
    build.onEnd((result) => {
      for (const output of result.outputFiles || []) {
        const sizeKB = output.contents.byteLength / 1024;
        const path = output.path;

        if (sizeKB > 50) {
          console.warn(`⚠️  ${path}: ${sizeKB.toFixed(1)}KB超過50KB區塊限制`);
        }
      }
    });
  },
};

const deadCodeEliminationPlugin: Plugin = {
  name: 'dead-code-elimination',
  setup(build) {
    build.onEnd((result) => {
      const content = result.outputFiles?.[0]?.text || '';
      const deadCodePatterns = [
        /if\s*\(\s*false\s*\)/g,
        /if\s*\(\s*true\s*\)\s*\{/g,
        /\/\/\s*@ts-ignore/g,
      ];

      for (const pattern of deadCodePatterns) {
        const matches = content.match(pattern);
        if (matches && matches.length > 0) {
          console.warn(`⚠️  可能的死程式碼: ${matches.length}處${pattern}`);
        }
      }
    });
  },
};

async function buildOptimized(): Promise<void> {
  await build({
    entryPoints: ['src/index.ts'],
    bundle: true,
    minify: true,
    treeShaking: true,
    format: 'esm',
    target: 'es2022',
    outdir: 'dist',
    metafile: true,
    splitting: true,
    plugins: [sizeLimitPlugin, deadCodeEliminationPlugin],
    external: ['react', 'react-dom', 'zod'],
    define: {
      'process.env.NODE_ENV': '"production"',
    },
    logLevel: 'info',
  });
}

buildOptimized();

執行時效能Profile

// src/monitoring/profiler.ts - 執行時效能分析器
interface ProfileEntry {
  operation: string;
  startTime: number;
  endTime: number;
  duration: number;
  memoryBefore: number;
  memoryAfter: number;
  memoryDelta: number;
}

class RuntimeProfiler {
  private entries: ProfileEntry[] = [];
  private readonly maxEntries = 500;

  profile<T>(operation: string, fn: () => T): T {
    const memBefore = process.memoryUsage().heapUsed;
    const startTime = performance.now();

    try {
      return fn();
    } finally {
      const endTime = performance.now();
      const memAfter = process.memoryUsage().heapUsed;

      this.entries.push({
        operation,
        startTime,
        endTime,
        duration: endTime - startTime,
        memoryBefore: memBefore,
        memoryAfter: memAfter,
        memoryDelta: memAfter - memBefore,
      });

      if (this.entries.length > this.maxEntries) {
        this.entries = this.entries.slice(-this.maxEntries);
      }
    }
  }

  async profileAsync<T>(operation: string, fn: () => Promise<T>): Promise<T> {
    const memBefore = process.memoryUsage().heapUsed;
    const startTime = performance.now();

    try {
      return await fn();
    } finally {
      const endTime = performance.now();
      const memAfter = process.memoryUsage().heapUsed;

      this.entries.push({
        operation,
        startTime,
        endTime,
        duration: endTime - startTime,
        memoryBefore: memBefore,
        memoryAfter: memAfter,
        memoryDelta: memAfter - memBefore,
      });

      if (this.entries.length > this.maxEntries) {
        this.entries = this.entries.slice(-this.maxEntries);
      }
    }
  }

  getHotspots(thresholdMs: number = 10): ProfileEntry[] {
    return this.entries
      .filter((e) => e.duration > thresholdMs)
      .sort((a, b) => b.duration - a.duration);
  }

  getMemoryHotspots(thresholdBytes: number = 1024 * 100): ProfileEntry[] {
    return this.entries
      .filter((e) => e.memoryDelta > thresholdBytes)
      .sort((a, b) => b.memoryDelta - a.memoryDelta);
  }

  generateReport(): string {
    const lines: string[] = [
      '### 執行時效能Profile\n',
      '#### 時間熱點 (>10ms)',
    ];

    for (const entry of this.getHotspots()) {
      lines.push(
        `- **${entry.operation}**: ${entry.duration.toFixed(2)}ms, ` +
        `記憶體: ${(entry.memoryDelta / 1024).toFixed(1)}KB`
      );
    }

    lines.push('\n#### 記憶體熱點 (>100KB)');
    for (const entry of this.getMemoryHotspots()) {
      lines.push(
        `- **${entry.operation}**: ${(entry.memoryDelta / 1024).toFixed(1)}KB, ` +
        `時間: ${entry.duration.toFixed(2)}ms`
      );
    }

    return lines.join('\n');
  }
}

const profiler = new RuntimeProfiler();

// 使用範例
const users = profiler.profile('fetchUsers', () => {
  return Array.from({ length: 1000 }, (_, i) => ({
    id: `user-${i}`,
    name: `使用者 ${i}`,
    email: `user${i}@example.com`,
  }));
});

const result = profiler.profile('processUsers', () => {
  return users.filter((u) => u.email.includes('example')).map((u) => u.name);
});

console.log(profiler.generateReport());

方案對比

最佳化維度 tsc增量編譯 Project References tsup/esbuild Vite Turbopack
編譯速度 ★★★ ★★★★ ★★★★★ ★★★★★ ★★★★★
設定複雜度
增量支援 否(全量但極快)
型別檢查 內建 內建 外置(tsc) 外置(tsc) 外置(tsc)
Tree-Shaking
Bundle大小 N/A N/A
適用場景 函式庫開發 大型專案 函式庫/工具 Web應用 Next.js
生產就緒 ★★★★★ ★★★★★ ★★★★★ ★★★★★ ★★★★
執行時最佳化 型別守衛最佳化 Branded Types const assertions 生成器 分層校驗
效能提升 ★★★★ ★★★ ★★ ★★★ ★★★★
程式碼侵入
型別安全 ★★★ ★★★★★ ★★★★★ ★★★ ★★★★
學習成本
適用場景 熱路徑 ID型別 常數設定 大資料集 API邊界

TypeScript效能最佳化不是「錦上添花」,而是生產專案的「生命線」。 編譯時用Project References和增量編譯提速10倍,建構時用tsup/esbuild替代tsc獲得tree-shaking,執行時避免熱路徑型別守衛,記憶體用Branded Types和const assertions減少膨脹,生產用效能預算和型別覆蓋率守住底線。效能不是最佳化出來的,是設計出來的——從專案第一天就配好Project References,從第一個模組就用明確匯出,從第一個型別就用const assertion。


推薦工具

  • JSON格式化 — 格式化tsconfig和建構產物JSON,快速排查設定問題
  • 程式碼格式化 — 格式化TypeScript程式碼,統一團隊程式碼風格
  • cURL轉程式碼 — 將API請求轉為型別安全的TypeScript fetch程式碼

本站提供瀏覽器本地工具,免註冊即可試用 →

#TypeScript性能#类型优化#编译加速#运行时优化#TypeScript 5.5#2026#前端工程