TS 类型工具 : Record的使用用例

1,928 阅读3分钟

在 TypeScript 中,Record 是一个强大的内置工具类型,用于创建 键值映射关系的对象类型。它特别适合需要严格约束对象的 键类型值类型 的场景。以下通过具体场景和示例来详细说明它的用法:


一、基础语法

type Record<K extends keyof any, T> = {
  [P in K]: T;
};
  • K: 表示对象的键类型(必须是 string | number | symbol 的子类型)
  • T: 表示对象的值类型

二、核心使用场景

1. 定义固定结构的配置对象

// 定义按钮配置类型
type ButtonConfig = Record<"submit" | "cancel" | "reset", { 
  color: string;
  size: number 
}>;

// 正确使用
const buttons: ButtonConfig = {
  submit: { color: "blue", size: 32 },
  cancel: { color: "red", size: 28 },
  reset: { color: "gray", size: 28 }
};

// 错误示例:缺少 required 键或类型不匹配
const wrongButtons: ButtonConfig = {
  submit: { color: "blue" }, // 错误:缺少 size
  unknownKey: { color: "red", size: 28 } // 错误:多余的键
};

2. 动态映射关系

// 将 API 端点映射到 URL
type ApiEndpoints = Record<"user" | "product" | "order", string>;

const apiConfig: ApiEndpoints = {
  user: "/api/users",
  product: "/api/products",
  order: "/api/orders"
};

// 访问时自动推断类型
const userEndpoint = apiConfig.user; // string 类型

3. 替代枚举的键值对

// 比枚举更轻量的状态码映射
type HttpStatus = Record<200 | 404 | 500, string>;

const statusMessages: HttpStatus = {
  200: "OK",
  404: "Not Found",
  500: "Internal Error"
};

// 自动提示键名,避免拼写错误
console.log(statusMessages[404]); // "Not Found"

三、与索引签名的区别

普通索引签名允许任意键名,而 Record 可以更精确控制:

// 索引签名:允许任意 string 键
type LooseObject = {
  [key: string]: number;
};

// Record:可限制键名为特定集合
type StrictKeys = Record<"width" | "height", number>;

const obj1: LooseObject = { anyKey: 10 }; // ✅ 允许
const obj2: StrictKeys = { width: 100, height: 200 }; // ✅
const obj3: StrictKeys = { other: 300 }; // ❌ 不允许未知键

四、在 Vue 组件中的应用示例

结合用户之前的错误场景,假设需要定义一个响应式配置对象:

<script lang="ts" setup>
import { reactive } from 'vue';

// 定义配置类型
type ThemeConfig = Record<"primary" | "secondary" | "error", string>;

// 使用 Record 约束响应式对象
const theme = reactive<ThemeConfig>({
  primary: "#409EFF",
  secondary: "#67C23A",
  error: "#F56C6C"
});

// 错误示例:缺少 required 键
const wrongTheme = reactive<ThemeConfig>({
  primary: "blue" // ❌ 缺少 secondary 和 error
});
</script>

五、高级用法

1. 联合类型键的动态生成

type Keys = "id" | "createdAt";
type Entity = Record<Keys, string> & {
  // 可扩展其他属性
  metadata?: object;
};

const user: Entity = {
  id: "001",
  createdAt: "2023-01-01",
  metadata: { role: "admin" }
};

2. 递归 Record 结构

// 定义树状结构
type Tree<T> = Record<string, T | Tree<T>>;

const categoryTree: Tree<number> = {
  electronics: {
    phones: 120,
    laptops: 85
  },
  books: 45
};

六、为何能避免用户之前的错误?

用户之前的错误包含 Parsing error: Missing initializer in const declaration,这通常是由于 TypeScript 未能正确解析类型导致的。使用 Record 可以:

  1. 明确类型结构:提前定义对象应有的键和值类型
  2. 编译时校验:在编码阶段捕获属性缺失或类型不匹配
  3. 代码提示增强:IDE 能基于 Record 的类型定义提供自动补全

通过合理使用 Record,可以显著提升代码的类型安全性和可维护性,尤其适用于 Vue 组件的 Props 定义、状态管理、配置对象等场景。