字符串与数字索引签名
理解数字键的规则与特殊之处。
字符串与数字索引签名 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。
索引 keys 的两种类型
TypeScript 同时支持字符串索引签名和数字索引签名。它们看起来相似,但由于 JavaScript 实际存储对象 keys 的方式不同,行为也不同。
数字索引签名
数字索引签名 { [i: number]: T } 描述的是通过数字位置进行索引的对象——最典型的就是数组和类数组结构。
type NumberList = { [index: number]: string }
const names: NumberList = { 0: "ana", 1: "leo" }
console.log(names[0]) // anaJS 会将数字键转换为字符串
这里有一个关键事实:JavaScript 对象的 keys 始终是字符串。当您写下 obj[0] 时,引擎实际会将键存储为字符串 "0"。TypeScript 对这一事实进行了建模。
const obj: Record<string, string> = {}
obj[1] = "one"
console.log(obj["1"]) // one — same key!
console.log(Object.keys(obj)) // ["1"]兼容性规则
由于数字键在底层实际上是字符串,TypeScript 强制执行一条规则:当对象同时具有数字索引签名和字符串索引签名时,数字索引的值类型必须可以赋值给字符串索引的值类型。
interface Mixed {
[key: string]: string
[index: number]: string // must match the string value type
}
const m: Mixed = { 0: "a", name: "b" }
console.log(m[0], m.name)为什么存在这条规则
如果 obj[0] 和 obj["0"] 指向同一个位置,那么该值的类型不能对前者是数字、对后者却是字符串。因此,为了保持一致,数字索引的值类型必须是字符串索引值类型的子类型。
// This is an ERROR:
// interface Bad {
// [key: string]: string
// [index: number]: number // number not assignable to string
// }数字索引:数组
数组是典型的数字索引类型。内置的 Array<T> 类型实际上具有数字索引签名,因此 arr[i] 会返回 T。
const nums: number[] = [10, 20, 30]
const first: number = nums[0]
console.log(first + nums[2]) // 40元组同样使用数字索引
元组建立在数字索引之上,但会将特定位置固定为特定类型。访问范围之外的数字位置时,结果会退化为元素类型的联合,或者被标记为错误。
const pair: [string, number] = ["age", 30]
const label: string = pair[0]
const value: number = pair[1]
console.log(label + ": " + value)字符串索引允许两种查找方式
具有字符串索引签名的对象仍然接受看起来像数字的访问方式,因为数字会先被转换为字符串键。
type Bag = { [key: string]: number }
const b: Bag = {}
b[5] = 100 // stored as key "5"
console.log(b["5"]) // 100数字索引不接受字符串
反过来则不成立。只有数字索引签名的对象会在编译时拒绝字符串键,即使 JS 在技术上允许这样做。
type OnlyNumbers = { [i: number]: string }
const o: OnlyNumbers = { 0: "x" }
// o.name = "y" // Error: property name not on number-indexed type
console.log(o[0])如何在两者之间选择
对于类似序列、基于位置的数据(列表、元组),请使用数字索引。对于按名称查找的数据(字典、缓存),请使用字符串索引。如果无法确定,字符串索引是更通用的选择。
type Positions = { [i: number]: { x: number; y: number } }
type ByName = { [name: string]: { x: number; y: number } }
const p: Positions = { 0: { x: 1, y: 2 } }
console.log(p[0].x)实际的混合对象
当一种值类型同时适用于两种签名时,您可以将它们组合起来——这适用于稀疏的类数组容器,同时还可以公开具名位置。
interface Flexible {
[key: string]: number
[index: number]: number
}
const f: Flexible = { 0: 1, total: 99 }
console.log(f[0] + f.total) // 100快速检查
测试您对字符串索引签名和数字索引签名区别的掌握程度。
回顾
字符串索引签名和数字索引签名之所以不同,是因为 JS 会将所有 keys 存储为字符串,并将数字转换为字符串键。当两者同时存在时,数字索引的值类型必须可以赋值给字符串索引的值类型。数字索引用于建模数组和元组;字符串索引用于建模字典。字符串索引对象接受数字访问,但数字索引对象会在编译时拒绝字符串键。
常见问题解答
「字符串与数字索引签名」课时是免费的吗?
是的 — 「字符串与数字索引签名」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。
「字符串与数字索引签名」这节课中我会学到什么?
理解数字键的规则与特殊之处。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 TypeScript Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「字符串与数字索引签名」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 TypeScript Academy 课中编写并运行代码吗?
能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 定义索引签名
- 字符串与数字索引签名
- 组合已知键与动态键
- 索引签名与 Record