keyof&in关键字
在 TypeScript 的类型操作中,keyof 和 in 经常一起出现:keyof 用来“取键”,in 用来“遍历键”(映射类型 / Mapped Types)。组合起来就能实现很多常见高级类型(如 Partial、Required 等)。
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 不能作为对象 key1.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的每一个属性名PT[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 | 5005. 小结
keyof:把对象类型的属性名提取为联合类型keyof any:对象 key 的可能类型string | number | symbolin:在映射类型中遍历联合类型(或keyof T)生成新类型-?/+?:在映射类型中移除/添加可选标记,常用于实现Required/Partial