TypeScript 索引类型
索引类型指三类能力:用 keyof 查询对象的键、用 T[K] 访问属性的值类型、用 [key: T] 声明索引签名。它们让类型可以像"查字典"一样动态取用,是写通用工具类型的常用手段。
keyof:索引类型查询
keyof 返回对象所有键组成的联合类型:
interface User {
name: string;
age: number;
vip: boolean;
}
type UserKey = keyof User; // "name" | "age" | "vip"
const k: UserKey = "age"; // 合法
// const bad: UserKey = "email"; // 编译错误
对数组取 keyof 会得到索引与内置成员:keyof string[] 为 number | "length" | 方法名等。
索引访问类型 T[K]
用方括号取出某个键对应的值类型,键可以是字面量或联合:
type Name = User["name"]; // string
// 一次取多个键,结果是联合
type Basic = User["name" | "age"]; // string | number
// 用 number 取数组元素类型
type Items = string[];
type Item = Items[number]; // string
type All = User[keyof User]; // string | number | boolean
泛型与 keyof 约束
泛型参数写成 K extends keyof T,返回值写作 T[K],即可写出安全的取值函数:
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const u: User = { name: "王五", age: 28, vip: true };
console.log(getProp(u, "name")); // 输出:王五
console.log(getProp(u, "age")); // 输出:28
// getProp(u, "email"); // 编译错误:email 不是 User 的键
不存在的键在编译期就被拦截,比 any 索引安全得多。
索引签名
当键名不固定时用索引签名描述"键的类型 → 值的类型":
interface Dict {
[key: string]: number; // 任意字符串键,值必须是 number
}
const scores: Dict = { math: 95, english: 88 };
console.log(scores.math); // 输出:95
console.log(scores["english"]); // 输出:88
// 限制取值类型不匹配会报错
// const bad: Dict = { name: "张三" }; // 编译错误
数字索引与字符串索引并存时,数字索引的值类型必须是字符串索引的子类型。
小结
keyof 负责"有哪些键",T[K] 负责"键对应什么类型",索引签名负责"动态键如何约束"。三者合起来,就能写出 getProp、Pick、Record 这类按需取用的通用类型工具。