树码科技 | 技术博客

TypeScript 索引签名

2026/04/14
22
0

引言

索引签名允许你定义对象的的类型约束。通过索引签名,可以确保对象的动态属性名和属性值符合指定的类型规则。索引签名分为字符串索引签名数字索引签名两种核心类型。

字符串索引签名

字符串索引签名用于约束对象的属性键为字符串类型,所有字符串键对应的属性值必须遵守约定的类型。 这是开发中最常用的索引签名,适用于动态键名的普通对象。

interface StringIndexedObject {
  // 字符串索引签名:键为 string,值为 number
  [key: string]: number;
}

const example: StringIndexedObject = {
  apple: 1,
  banana: 2,
};

// 合法:动态添加字符串键
example.orange = 3;
// 报错:值类型不匹配
// example.grape = "error";

在这个例子中:

  • [key: string]: number 是标准的字符串索引签名

  • 对象的所有字符串类型的键,对应的值必须是 number 类型

  • 无论是初始赋值还是动态添加属性,都会受到严格的类型约束

数字索引签名

数字索引签名用于约束对象的属性键为数字类型,所有数字键对应的属性值必须遵守约定的类型。 在 JavaScript 中,数字键会被自动转换为字符串,但 TypeScript 会严格校验索引类型。

interface NumberIndexedObject {
  // 数字索引签名:键为 number,值为 string
  [key: number]: string;
}

const example: NumberIndexedObject = {
  1: 'one',
  2: 'two',
};

// 合法:数字键赋值
example[3] = 'three';
// 报错:值类型不匹配
// example[4] = 4;

补充:JavaScript 数组的本质就是数字索引签名,string[] 等价于 { [index: number]: string }

混合索引签名

TypeScript 支持同时定义字符串和数字两种索引签名,但有强制语法规则数字索引签名的值类型,必须是字符串索引签名值类型的子类型。 这是因为 JavaScript 会将数字键自动转为字符串,TypeScript 需要以此保证类型安全。

interface MixedIndexedObject {
  [key: string]: string | number;
  [key: number]: string;
}

const example: MixedIndexedObject = {
  1: 'one',
  2: 'two',
  'apple': 1,
  'banana': 'yellow'
};

在这个例子中:

  • 数字索引的值类型 string 是字符串索引值类型 string | number 的子类型,符合 TS 强制规则

  • 对象可同时包含数字键和字符串键,且值类型完全满足约束要求

注意事项

  1. 固定属性兼容规则 接口内的显式属性,类型必须兼容索引签名的值类型,否则会报错

  2. 只读索引签名 可搭配 readonly 限制属性不可修改:readonly [key: string]: number

  3. 约束范围 一旦定义索引签名,对象的所有属性都必须遵循该签名的类型规则

索引签名与 Record

Record<K, T> 是 TypeScript 内置的泛型工具类型,底层基于索引签名实现,是索引签名的简化语法糖:

// 两种写法完全等价
type Obj1 = Record<string, number>;
type Obj2 = { [key: string]: number };

总结

  1. 核心作用:索引签名用于约束动态键名对象的键类型和值类型;

  2. 两种形式:字符串索引(常用)、数字索引(数组底层实现);

  3. 混合规则:数字索引的值类型必须是字符串索引值类型的子类型;

  4. 语法糖Record 类型是索引签名的简化写法,二者功能完全一致。