typescript索引签名用于定义对象可拥有动态键名,支持字符串和数字索引,值类型需兼容已有属性;推荐用record替代手写索引签名以提升类型安全与可读性。

在 TypeScript 中,索引签名(Index Signature)用于定义对象可以拥有**动态、未知名称的属性**,即键名不是预先写死的字符串字面量,而是符合某种模式(如任意字符串或数字),同时统一约束其值的类型。
基本语法:用 [key: Type] 声明索引签名
最常见的是字符串索引签名,语法为 [key: string]: ValueType。它表示:该对象允许任意字符串作为键,所有这类键对应的值都必须是 ValueType 类型。
- ✅ 正确示例:
interface User {
name: string;
[key: string]: string | number; // 允许额外任意字符串键,值只能是 string 或 number
}
const u: User = {
name: "Alice",
age: 30, // ✅ 合法:age 是 string 键,值是 number
city: "Beijing", // ✅ 合法:city 是 string 键,值是 string
};
- ⚠️ 注意限制:
如果接口中已有明确属性(如 name: string),索引签名的值类型必须能兼容这些已有属性的类型。上例中 name 是 string,所以索引签名的值类型必须包含 string(如 string | number 是 OK 的;但只写 number 就会报错)。
支持数字索引签名,常用于类数组对象
除了字符串,也可用 number 作为索引类型,通常配合数值下标访问,例如模拟数组行为:
interface StringList {
[index: number]: string;
}
const list: StringList = ["a", "b", "c"]; // ✅ 兼容数组字面量
console.log(list[0]); // "a"
注意:若同时声明了字符串和数字索引签名,**数字索引的值类型必须是字符串索引值类型的子类型**(因为 JavaScript 中数字键会被自动转成字符串)。例如下面合法:
interface Hybrid {
[index: number]: string;
[key: string]: string | number; // ✅ number 是 string|number 的子类型
}
但反过来会报错。
用 Record 替代手写索引签名(更推荐)
对于“键是某类字符串、值是某类型的映射”,TypeScript 内置泛型 Record<keyunion valuetype></keyunion> 更清晰安全:
- 适用于已知键集合(如枚举、字面量联合):
type Status = "active" | "inactive" | "pending";
type UserStatus = Record<status date>;
const statusMap: UserStatus = {
active: new Date(),
inactive: new Date(),
pending: new Date(),
};</status>
- 也支持任意字符串键(类似索引签名):
type DynamicConfig = Record<string string boolean>;
const config: DynamicConfig = {
timeout: "30s",
debug: true,
host: "api.example.com",
};</string>
Record<string t></string> 在语义和类型推导上通常比 [key: string]: T 更友好,尤其在泛型和工具类型组合时。
实际使用建议与避坑点
- 索引签名不支持联合类型作为键(如
[key: "id" | "name"]❌),这是字面量类型,应直接写属性或用Record; - 想让对象**只允许特定键**,不要用索引签名,而应使用精确类型(如
keyof+ 映射)或as const+ 字面量类型; - 索引签名无法捕获“键是否存在”的运行时逻辑,它只做静态类型检查;真正做动态键校验需配合
in操作符或Object.hasOwn(); - 避免过度使用
[key: string]: any—— 这会严重削弱类型安全性,尽量明确值类型或用unknown+ 类型守卫。











