in 运算符的作用是什么?
下文默认基于 TypeScript 5.x。
in既有运行时用法,也有类型层面的用法,面试里最好分开答。
面试速答(30 秒版 TL;DR)
- 在运行时,
in用来判断“某个属性名是否存在于对象中”,包括原型链上的属性。 - 在 TypeScript 里,
in还常出现在:- 联合对象类型收窄;
- 映射类型(mapped types)。
- 所以这道题别只答一半。比较完整的答法是:
- 值层面:属性存在性判断;
- 类型层面:遍历键名生成新类型。
1. 运行时里的 in
const user = {
name: "Tom",
};
console.log("name" in user); // true
console.log("toString" in user); // true
console.log("age" in user); // false
这里最容易丢分的一点是:
in判断的不只是对象“自有属性”;- 它连原型链上的属性也会算进去。
所以:
"toString" in user; // true
2. in 和 hasOwnProperty 有什么区别
很多面试官会追问这个。
in:看对象本身 + 原型链;Object.hasOwn(obj, key)或hasOwnProperty:只看对象自身属性。
const obj = Object.create({ inherited: true });
obj.self = true;
console.log("inherited" in obj); // true
console.log(Object.hasOwn(obj, "inherited")); // false
所以如果你的语义是“这个字段是不是对象自己真的定义了”,那就不要只用 in。
3. TypeScript 里常用它做联合类型收窄
type Cat = {
meow: () => void;
};
type Dog = {
bark: () => void;
};
function speak(animal: Cat | Dog) {
if ("meow" in animal) {
animal.meow();
} else {
animal.bark();
}
}
这里 in 的意义是:
- 运行时判断这个属性是否存在;
- 编译期顺带帮助 TypeScript 把联合类型缩小。
这是前端业务代码里最常见的用法之一。
4. 用 in 判断 unknown 时要先保护对象分支
function readId(value: unknown) {
if (
typeof value === "object" &&
value !== null &&
"id" in value
) {
return value.id;
}
return undefined;
}
原因是:
in左边是属性名;- 右边必须是对象类型;
null和原始值都不能直接拿来做这个判断。
5. 类型层面的 in:映射类型
这是 TypeScript 面试里另一个高频点。
type Keys = "name" | "age";
type User = {
[K in Keys]: string;
};
等价于:
type User = {
name: string;
age: string;
};
所以这里的 in 不是运行时运算符语义,而是:
- 遍历一个联合键集合;
- 为每个键生成一份属性定义。
常见例子:
type ReadonlyUser<T> = {
readonly [K in keyof T]: T[K];
};
这就是很多工具类型的基础。
6. 高频面试题标准答法
6.1 in 能不能判断属性值是不是 undefined
不能直接这么理解。
in 判断的是“键是否存在”,不是“值是否有意义”。
const obj = { name: undefined };
console.log("name" in obj); // true
6.2 为什么 in 可以帮助联合类型收窄
因为如果某个分支独有某个属性,那么一旦该属性存在,编译器就能推断当前值更接近哪个分支。
6.3 映射类型里的 in 和运行时 in 是一个东西吗
不是一个层级:
- 运行时
in是 JavaScript 运算符; - 映射类型里的
in是 TypeScript 类型系统语法。
7. 常见误区
- 误区 1:以为
in只检查对象自有属性。- 它会沿原型链查。
- 误区 2:以为
in是判断值是否不为undefined。- 它判断的是键是否存在。
- 误区 3:只记住运行时用法,不知道它还能用于映射类型。
速记要点
- 值层面的
in:判断属性名是否存在于对象或其原型链上。 - 类型层面的
in:遍历键集合生成新类型。 - 联合对象分支判断时,
in是很常见的收窄手段。