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 这类按需取用的通用类型工具。

笔记加载中…