面试题答案
一键面试1. 实现 DeepPartial
类型
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
2. TypeScript 类型推断机制
TypeScript 的类型推断是在编译时自动分析代码中值的类型的过程。当定义变量、函数参数、返回值等时,如果没有显式指定类型,TypeScript 会根据赋值的表达式来推断类型。例如:
let num = 10; // num 被推断为 number 类型
function add(a, b) {
return a + b;
}
// add 函数的参数 a 和 b 被推断为 any 类型,返回值被推断为 any 类型
在泛型函数或类型中,类型推断根据传入的参数或使用场景来确定泛型类型。例如:
function identity<T>(arg: T): T {
return arg;
}
let result = identity(5); // T 被推断为 number 类型
3. 利用条件类型、映射类型实现 DeepPartial
- 映射类型:在
DeepPartial
中,[P in keyof T]
使用了映射类型。它遍历类型T
的所有键,并为每个键创建一个新的属性。keyof T
获取类型T
的所有键,P
代表每个键。 - 条件类型:虽然在
DeepPartial
的基本实现中没有直接使用条件类型,但在更复杂的类型转换中可能会用到。条件类型的语法是T extends U? X : Y
,表示如果T
可以赋值给U
,则类型为X
,否则为Y
。例如:
type IsString<T> = T extends string? true : false;
type StringCheck = IsString<string>; // true
type NumberCheck = IsString<number>; // false
在 DeepPartial
中,?
使属性变为可选,并且递归地应用 DeepPartial
到子属性,实现了深度可选化。
4. 处理深层次嵌套对象和循环引用对象的挑战及解决方法
- 深层次嵌套对象:
- 挑战:随着嵌套层次的增加,类型计算的复杂度会指数级增长,可能导致编译时间变长。
- 解决方法:可以通过控制嵌套深度来缓解,例如限制递归的层数。在某些场景下,如果嵌套深度已知,可以手动编写有限层的
DeepPartial
类型。例如,对于两层嵌套的对象:
type ShallowDeepPartial<T> = {
[P in keyof T]?: {
[Q in keyof T[P]]?: T[P][Q];
};
};
- 循环引用对象:
- 挑战:TypeScript 的类型系统是基于静态分析的,循环引用会导致类型检查陷入无限循环,无法得出结果。
- 解决方法:在定义类型时避免循环引用。如果在运行时可能出现循环引用,可以在处理数据时通过额外的逻辑来检测和处理循环,例如使用
WeakMap
来记录已经处理过的对象,防止重复处理。在类型层面,可以通过引入中间类型,打破循环引用的直接关联。例如:
// 假设我们有两个相互引用的类型 A 和 B
// 错误示例(直接循环引用)
// type A = { b: B };
// type B = { a: A };
// 正确示例(通过中间类型打破循环)
type ARef = { b: BRef };
type BRef = { a: ARef };
type A = { b: B };
type B = { a: A };
这样在类型定义时避免了直接循环引用,同时在运行时可以通过 ARef
和 BRef
来处理数据结构,防止无限循环。