keyof&in关键字

2026 年 2 月 17 日 星期二
6

keyof&in关键字

在 TypeScript 的类型操作中,keyofin 经常一起出现:keyof 用来“取键”,in 用来“遍历键”(映射类型 / Mapped Types)。组合起来就能实现很多常见高级类型(如 PartialRequired 等)。


1. keyof:取对象键名的联合类型

keyof 操作符接受一个对象类型作为参数,返回该对象属性名组成的字面量联合类型。

type Dog = { name: string; age: number };
type D = keyof Dog; // "name" | "age"

1.1 keyof any 是什么?

在一些高级类型中经常会看到 keyof any

type K = keyof any; // string | number | symbol

原因是:在 TS 类型系统里,“对象的 key”可能是 string | number | symbol(也就是 JS/TS 中合法的属性键类型)。

它常与 extends 搭配,用于约束“可作为 key 的类型”:

type Key = string | number | symbol;

type Dict<K extends keyof any, V> = {
  [P in K]: V;
};

type A = Dict<"x" | "y", number>; // { x: number; y: number }
// type B = Dict<boolean, number>; // ❌ boolean 不能作为对象 key

1.2 遇到索引签名时的返回结果

当类型存在索引签名(Index Signature)时,keyof 的结果会体现索引签名的 key 类型。

type Dog = { [y: number]: number };
type DogKey = keyof Dog; // number

type Doggy = { [y: string]: boolean };
type DoggyKey = keyof Doggy; // string | number

type Doggy2 = { [y: string]: unknown; [x: number]: boolean };
type Doggy2Key = keyof Doggy2; // string | number

为什么当索引类型为 string 时,keyof 会返回 string | number

因为在 JavaScript 中,对象的属性键最终会被转换为字符串(数字键也会以字符串形式表现),因此 TS 会把 number 也包含进来。


2. in:遍历联合类型生成新类型(映射类型)

in 的右侧一般跟一个联合类型,表示对联合类型中的每个成员进行“迭代”,其效果类似 JS 的 for...in / for...of,但发生在类型层面

type Animals = "pig" | "cat" | "dog";

type AnimalMap = {
  [key in Animals]: string;
};

// type AnimalMap = {
//   pig: string;
//   cat: string;
//   dog: string;
// }

3. 实战:用 keyof + in 实现 Partial / Required

3.1 Partial<T>:全部属性变可选

思路:先用 keyof 取出 T 的所有 key,再用 in 遍历每个 key,并用 ? 把属性变成可选。

type MyPartial<T> = {
  [P in keyof T]?: T[P];
};

其中:

  • [P in keyof T] 表示遍历 T 的每一个属性名 P
  • T[P] 表示该属性名对应的属性值类型(可理解为取 value)

3.2 Required<T>:全部属性变必选

Partial 相反:把可选属性“去掉可选标记”。在映射类型里可以用 -? 移除可选标记。

type MyRequired<T> = {
  [P in keyof T]-?: T[P];
};

示例:

interface Props {
  a?: number;
  b?: string;
}

const obj: Props = { a: 5 }; // b 可选,所以没问题

// const obj2: MyRequired<Props> = { a: 5 }; // ❌ 缺少 b
// Property 'b' is missing in type '{ a: number; }' but required in type 'MyRequired<Props>'.

const obj3: MyRequired<Props> = { a: 5, b: "ok" }; // ✅

补充:与 -? 对应的还有 +?,用于显式添加可选标记(通常不写也会默认保持原样,但在某些组合场景会更清晰)。


4. 常见组合写法速记

4.1 “取值类型”常见写法:T[K]

type ValueOf<T, K extends keyof T> = T[K];

4.2 与 typeof 的常见搭配:keyof typeof

当你想从“值”推导类型,再取它的 key 时会用到:

const statusMap = {
  ok: 200,
  notFound: 404,
  error: 500,
} as const;

type StatusKey = keyof typeof statusMap; // "ok" | "notFound" | "error"
type StatusCode = (typeof statusMap)[StatusKey]; // 200 | 404 | 500

5. 小结

  • keyof:把对象类型的属性名提取为联合类型
  • keyof any:对象 key 的可能类型 string | number | symbol
  • in:在映射类型中遍历联合类型(或 keyof T)生成新类型
  • -? / +?:在映射类型中移除/添加可选标记,常用于实现 Required / Partial

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...