讲解

keyof 作用于一个对象类型,得到它所有键的联合:keyof { a: string; b: number } 是 "a" | "b"。它是连接「对象结构」和「字符串字面量」的桥梁——上一章的 pick 函数、表单的字段名参数、i18n 的文案 key,背后都是 keyof。对联合类型取 keyof 得到的是各成员键的交集(共有键),对 any 取 keyof 得到 string | number | symbol,这些边角了解即可。

typeof 则走另一个方向:从一个值拿到它的类型。JavaScript 本来就有运行时 typeof 运算符,TypeScript 在类型位置复用了这个关键字:const user = { name: "林" }; type User = typeof user 让类型跟随实现,改实现时类型自动更新,避免「两处定义、逐渐漂移」。配合 as const,typeof 是提取字面量联合的主力(枚举章节的 Theme 例子已经见过)。

两者经常联手:(typeof CONFIG)[keyof typeof CONFIG] 表示「CONFIG 所有值的联合类型」,是从常量对象提取「可取值范围」的标准公式。记住这三个操作的位置感:keyof 后是类型,typeof 后是值,T[K] 用类型索引出属性的类型——索引访问类型 T["a"] 本身也是一个独立技能,取嵌套结构里的某一层特别好用。

示例

keyof 得到键的联合:

interface Product {
  sku: string;
  name: string;
  price: number;
}

type ProductKey = keyof Product; // "sku" | "name" | "price"

function printField(product: Product, key: ProductKey): void {
  console.log(`${key} => ${String(product[key])}`);
}

const p: Product = { sku: "KB-001", name: "键盘", price: 299 };
printField(p, "name");
printField(p, "price");

typeof 从值提取类型,实现与类型同源:

const defaultOptions = {
  pageSize: 20,
  sort: "createdAt",
  asc: false,
};

type Options = typeof defaultOptions;

function buildQuery(overrides: Partial<Options>): Options {
  return { ...defaultOptions, ...overrides };
}

const q = buildQuery({ pageSize: 50 });
console.log(`每页 ${q.pageSize} 条,按 ${q.sort} 排序`);

索引访问类型取嵌套层级,配合 keyof + typeof 的公式:

const ROUTES = {
  home: "/",
  bookList: "/books",
  bookDetail: "/books/:id",
} as const;

type RoutePath = (typeof ROUTES)[keyof typeof ROUTES]; // "/" | "/books" | "/books/:id"
type BookDetailRoute = (typeof ROUTES)["bookDetail"]; // 精确取一层

function navigate(path: RoutePath): string {
  return `跳转到 ${path}`;
}

const detail: BookDetailRoute = ROUTES.bookDetail;
console.log(navigate(ROUTES.home), detail);

常见坑

  • keyof 用于具体值:keyof 后面必须是类型,对值要用 typeof 先转类型:keyof typeof config。
  • 以为 T[K] 是运行时取值:类型位置的 T[K] 是「属性类型查询」,发生在编译期;运行时取值是 obj[key],两者别混。
  • 对联合类型 keyof 结果吃惊:keyof (A | B) 是共有键的交集,不是并集——想操作各自键先收窄。
  • typeof 一个 any 值:得到 any,公式全部失效;源头的常量要有明确类型。

小结

keyof:类型 → 键的联合;typeof:值 → 类型;T[K]:类型 → 属性类型。三者组合出「跟随实现」的类型工具。下一章看官方造好的一篮子工具类型。