← 返回题目列表

keyof 和 typeof 在 TypeScript 中有什么用?

高频 中等 第 5 / 32 题 更新于 2026/07/27
TypeScriptkeyoftypeof

简化版

keyof 获取类型的键名联合,typeof 在类型位置可以从变量值推导出类型。二者常配合配置对象使用,让值和类型保持同步。

详细版

keyof

interface User {
  id: number;
  name: string;
}
type UserKey = keyof User; // 'id' | 'name'

类型位置的 typeof

const config = {
  theme: 'dark',
  pageSize: 20,
};
type Config = typeof config;
type ConfigKey = keyof typeof config;

常用于限制参数只能是对象已有 key:

function get<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

完整版教学

一、keyof 把对象类型的键变成联合类型

如果一个对象类型有 idnamekeyof 得到的就是 'id' | 'name'。这让 key 也能被类型系统约束。

function pickUser(key: keyof User) {}

传入不存在的 key 会被编译器拦住。

二、typeof 有两个世界

JavaScript 运行时的 typeof 用来判断值类型。TypeScript 类型位置的 typeof 用来获取变量的静态类型。

const user = { id: 1, name: 'Tom' };
type User = typeof user;

这里不会在运行时执行,它只是类型推导。

三、keyof typeof 的典型用法

const routes = {
  home: '/',
  about: '/about',
} as const;

type RouteName = keyof typeof routes;

这样新增或删除 routes 的 key,RouteName 自动变化,避免维护两份枚举。

四、泛型 get 函数体现类型关联

function get<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

返回值类型会根据 key 精确变化。传 'name' 返回 string,传 'id' 返回 number。这是 TS 类型系统非常实用的能力。

五、面试追问与工程落地

面试官常会追问 keyof any 是什么。它等价于 string | number | symbol,因为 JS 对象属性 key 的类型最终就是这三类。数组的 key 还会包含数字索引和一些数组方法名,所以对数组使用 keyof 时要小心。

另一个追问是 as const 的作用。没有 as const 时,对象里的字符串值可能被拓宽成 string;加上后会保留字面量类型并把属性推成 readonly。这对从配置对象推导联合类型很关键。

工程里 keyof typeof 很适合替代手写枚举,比如路由名、权限码、主题 key、埋点事件名。值和类型来自同一份配置,减少“配置改了类型忘改”的问题。

六、把键空间、值空间和运行时枚举分开

keyof 的结果不总是字面量键列表。字符串索引签名的键结果通常包含 string | number,因为 JavaScript 会把数字属性访问转成字符串;数字索引签名则得到 number。另一方面,运行时 Object.keys 只返回自有可枚举字符串键,不会因为静态类型写得更窄就自动返回 (keyof T)[]

type StringMap = { [key: string]: boolean }
type MapKey = keyof StringMap // string | number

const config = { dark: true, pageSize: 20 } as const
type Config = typeof config
type ConfigKey = keyof Config // 'dark' | 'pageSize'
type PageSize = Config['pageSize'] // 20
表达式所处世界示例结果
typeof valueJavaScript 运行时'object''string' 等字符串
type X = typeof valueTypeScript 类型位置值的静态类型
keyof XTypeScript 类型位置属性键联合
X[K]TypeScript 类型位置键 K 对应的值类型

上例配置有 2 个键,keyof typeof config 会自动产生 2 个成员;增加第 3 个配置项后,键联合也同步增加。as constpageSize 保留字面量 20 且属性只读,而不是拓宽成一般的 number

记忆顺序:typeof 从值走到类型,keyof 从对象类型走到键联合,T[K] 再从键走到对应值类型。

七、常见误区与追问

  • 误区:keyof 永远只会得到字符串字面量。 数字键、Symbol 键和索引签名都会改变结果,字符串索引签名常得到 string | number
  • 误区:类型位置的 typeof 会生成运行时代码。 它只查询静态类型,编译后被擦除,与 JavaScript 的 typeof 表达式用途不同。
  • 误区:Object.keys(obj) 的返回类型一定是 Array 对象运行时可能有类型声明外的额外键,因此标准签名通常返回 string[]
  • 追问:keyof any 是什么? 它是 string | number | symbol,对应 JavaScript 可用的属性键类型。
  • 追问:为什么 keyof 字符串索引类型包含 number? obj[0] 在 JavaScript 中会按字符串键访问,所以数字也可命中字符串索引签名。
  • 追问:as const 对 keyof 本身有什么帮助? 键通常本就保留,但它能保住值的字面量和 readonly 信息,便于继续从 typeof obj[keyof typeof obj] 推导值联合。
  • 追问:怎样写类型安全的 get 函数?<T, K extends keyof T>(obj: T, key: K): T[K] 同时约束键并关联返回值。

八、加强记忆

keyof 是“从类型拿键”,类型位置的 typeof 是“从值拿类型”。组合起来就是“从配置对象自动生成键名类型”。

遇到配置推导题就沿“值 → typeof 类型 → keyof 键 → T[K] 值”这条链推演,避免混淆运行时 API。