Skip to content

TypeScript 5.4:NoIntrinsic、Object.groupBy 與類型推斷增強

TypeScript 5.4 正式發佈,帶來了一些實用的類型系統改進和對 TC39 新提案的支持。從架構視角看,有幾個特性對團隊代碼質量提升明顯。

Object.groupBy 和 Map.groupBy

之前分組操作需要寫 reduce:

typescript
// 以前:手寫 reduce
const grouped = users.reduce((acc, user) => {
  const key = user.role;
  if (!acc[key]) acc[key] = [];
  acc[key].push(user);
  return acc;
}, {} as Record<string, User[]>);

// TypeScript 5.4 + ES2024
const grouped = Object.groupBy(users, (user) => user.role);
// grouped 的類型是 Partial<Record<string, User[]>>

返回 Partial 是合理的,因為分組結果可能不包含所有可能的 key。

Map.groupBy 則返回 Map<K, V[]>,支持任意類型作為 key:

typescript
const byDept = Map.groupBy(users, (u) => departments.get(u.deptId)!);
// 返回 Map<Department, User[]>

NoIntrinsic 類型安全增強

TypeScript 5.4 引入了 NoIntrinsic 類型,這是對模板字面量類型的增強。在處理 HTML 屬性映射時更精確:

typescript
// 類型推斷更精準,條件類型中交叉類型分發更正確
type ExtractId<T> = T extends `${infer Prefix}_${infer Suffix}`
  ? `${Prefix}_id`
  : never;

type Result = ExtractId<"user_name" | "post_title">;
// "user_id" | "post_id"

改進的閉包類型縮小

一個很實用的改進:閉包中捕獲的變量現在能正確保持類型縮小:

typescript
function processValue(input: string | number) {
  if (typeof input === "string") {
    // TS 5.4 之前:閉包中 input 可能丟失 string 類型
    const handler = () => {
      return input.toUpperCase(); // 現在能正確識別為 string
    };
  }
}

in 運算符的類型收窄增強

typescript
interface Dog {
  bark(): void;
}

interface Cat {
  meow(): void;
}

function handlePet(pet: Dog | Cat) {
  if ("bark" in pet) {
    pet.bark(); // TS 5.4 之前這裏可能不夠精確
  }
}

在項目中的落地

我們團隊在升級 TS 5.4 時,重點關注了幾個場景:

  1. 數據處理層:把自定義 groupBy 工具函數替換為原生 Object.groupBy,減少約 200 行重複代碼
  2. 類型安全:利用改進的條件類型推斷,簡化了 API 響應類型的自動推導
  3. 團隊規範:更新 ESLint 規則,檢測並標記可以使用原生 API 的地方

小結

  • Object.groupBy / Map.groupBy:原生分組 API,減少重複工具函數
  • 閉包類型縮小:閉包中捕獲的變量保持類型信息
  • in 運算符增強:更精確的類型收窄
  • 條件類型推斷改進:交叉類型處理更準確
  • 建議團隊統一升級,配合 target: "ES2024" 使用

MIT Licensed