keyof 用于从类型中提取所有可访问键名组成字符串字面量联合类型,仅作用于类型而非值,需配合 typeof 作用于变量;支持索引签名、内置方法键及数字键,但不递归提取嵌套属性。

keyof 的作用就是把一个对象类型里所有可访问的键名,提取成字符串字面量组成的联合类型。它不作用于变量,只作用于类型;不能直接用在运行时对象上,必须配合 typeof 先拿到类型。
keyof 只能用于类型,不是值
比如你有接口:
interface User { id: number; name: string; role: 'admin' | 'user'; }这时写 type UserKeys = keyof User,得到的就是 "id" | "name" | "role" —— 这是一个字面量联合类型,每个成员都是字符串字面量,不是 string。
如果误写成 keyof userInstance(其中 userInstance 是一个变量),TS 会报错,因为 keyof 后面必须跟类型,不能是值。
配合 typeof 获取对象变量的类型再提取键
当你有一个具体对象,想基于它推导键类型,得先用 typeof 把它转成类型:
const user = { id: 1, name: 'Alice', active: true };那么 type UserKeys = keyof typeof user 就等价于 "id" | "name" | "active"。
注意:typeof user 是推导出的匿名类型,不是接口;keyof 只对这个推导出的类型生效,不关心变量名或运行时内容。
支持数字、字符串索引签名和内置方法键
keyof 不仅提取显式定义的属性,还包含合法的隐式键:
- 对 interface T { 0: string; 'x': number },keyof T 是 0 | "x"
- 对数组类型 number[],keyof number[] 包含 "length" | "push" | "pop" | "0" | "1" | ... | number(数字索引 + 原型方法 + length)
- 对带字符串索引签名的类型 interface Dict { [k: string]: any },keyof Dict 是 string | number(因为 JS 中数字键会被转为字符串)
嵌套对象的键需要分层提取
keyof 不自动递归。比如:
type Config = { host: string; port: number; db: { name: string; timeout: number } };keyof Config 是 "host" | "port" | "db",不包括 "name" 或 "timeout"。
要取 db 内部的键,得单独处理:type DbKeys = keyof Config['db'] → "name" | "timeout"。


















