TypeScript 索引签名:动态对象的类型安全
索引签名为键名未知的动态对象提供类型安全:{ [key: string]: number }。本文讲解语法、与已知属性混用、string vs number 键。
索引签名描述"任意键、统一值类型"的对象:interface Dict { [key: string]: number }。键名编译期未知但值类型受控——字典、缓存、动态配置的类型化方案。已知属性可与索引签名共存,但必须兼容其值类型。
动态属性问题
const scores = {};
scores['数学'] = 95; // 普通类型推导对任意键无能为力
索引签名解法
interface ScoreMap {
[subject: string]: number;
}
const scores: ScoreMap = {};
scores['数学'] = 95; // ✓
scores['英语'] = '优秀'; // ✗ 编译错误:值必须是 number
键动态、值受控——字典结构的正确类型化。
与已知属性混用
interface Config {
name: string; // 已知属性
[key: string]: string; // 其他任意字符串键
}
约束:已知属性的类型必须兼容索引签名(name: string 兼容 [key: string]: string ✓;若索引签名是 number 则冲突)。
string vs number 键
JS 对象的键运行时都是字符串——number 索引签名([i: number]: T)专为类数组结构设计,访问时数字键自动转字符串仍类型安全。
Record:更常用的封装
type ScoreMap = Record<string, number>; // 等价于索引签名
type RouteTable = Record<string, RouteConfig>;
语义相同、写法更短——日常用 Record,接口中混用时用索引签名。
常见问题(FAQ)
Q:索引签名和 Map 怎么选?
键是字符串且需要序列化(JSON)用对象+索引签名;键任意类型、需迭代顺序、频繁增删用 Map——Map 的类型是 Map<K, V> 天然精确。
Q:索引签名会让"不存在的键"不报错吗?
会——这正是它的语义(任意键合法)。拼写检查需求强的场景用精确接口而非索引签名。
Q:noUncheckedIndexedAccess 是什么?
严格选项:索引访问返回 T | undefined——逼你处理键不存在的情况。大型项目建议开启,配合可选链使用。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。