TypeScript高级类型:条件类型与映射类型实战
在TypeScript的进阶面试中,高级类型系统是考察开发者深度理解能力的重要领域。其中,条件类型和映射类型是构建复杂、灵活且类型安全的代码库的两大核心支柱。本文将通过实战案例和面试常见问题,深入解析这两类高级类型。
一、条件类型:类型层面的“条件判断”
条件类型的语法类似于三元表达式:T extends U ? X : Y。它根据类型T是否可以赋值给类型U,来决定最终的类型是X还是Y。这是实现类型逻辑分支的基础。
1.1 基础示例与类型推断
type IsString<T> = T extends string ? true : false;
type A = IsString<'hello'>; // true
type B = IsString<number>; // false
// 结合 infer 关键字进行类型提取(常见面试点)
type ExtractReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Func = () => number;
type Return = ExtractReturnType<Func>; // number
1.2 分布式条件类型
当条件类型作用于联合类型,并且T是裸类型参数时,会发生“分发”效果。这是面试中的高频考点。
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>;
// 等价于 ToArray<string> | ToArray<number>
// 最终结果是 string[] | number[]
// 注意:不是 (string | number)[]
理解分发条件类型,对于处理联合类型的转换至关重要。
二、映射类型:批量变换类型的“蓝图”
映射类型基于旧类型创建新类型,通过遍历旧类型的键(keyof T)并对每个键应用某种变换规则。
2.1 内置工具类型实现原理
TypeScript内置的Partial<T>、Readonly<T>、Pick<T, K>等工具类型,其底层都是映射类型。
// Partial<T> 的实现原理
type MyPartial<T> = {
[P in keyof T]?: T[P];
};
// Readonly<T> 的实现原理
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
};
interface User {
id: number;
name: string;
email: string;
}
type PartialUser = MyPartial<User>;
// { id?: number; name?: string; email?: string; }
2.2 键重映射(as 子句)
TypeScript 4.1引入了键重映射(Key Remapping),功能更加强大,允许在映射过程中修改键名。
type Getters<T> = {
[P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};
interface Person {
name: string;
age: number;
}
type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number; }
三、实战结合:打造类型安全的工具
将条件类型与映射类型结合,可以解决许多复杂的类型编程问题。
3.1 实现一个“条件属性”类型
根据某个条件,决定是否包含特定属性。
type ConditionalProps<T, Condition> = {
[K in keyof T as T[K] extends Condition ? K : never]: T[K];
};
interface Data {
id: number;
name: string;
tags: string[];
createdAt: Date;
}
// 只提取出值是 string 类型的属性
type StringProps = ConditionalProps<Data, string>; // { name: string }
3.2 面试实战题:深度可选(DeepPartial)
实现一个DeepPartial<T>,将嵌套对象的所有属性都变为可选。这考察了对递归类型和映射类型的综合运用。
type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;
interface Company {
name: string;
address: {
city: string;
street: string;
};
}
type PartialCompany = DeepPartial<Company>;
/*
{
name?: string;
address?: {
city?: string;
street?: string;
};
}
*/
在处理这类复杂类型转换时,清晰的思路至关重要。就像使用专业的数据库工具能极大提升效率一样,在数据库开发中,dblens SQL编辑器提供了智能补全、语法高亮和跨数据库支持,能帮助开发者快速、准确地编写和调试复杂SQL,从而更专注于业务逻辑而非语法细节。
四、总结与最佳实践
- 条件类型是类型系统的“控制流”,用于实现类型层面的条件判断和类型提取(
infer)。 - 映射类型是类型系统的“循环与变换”,用于批量生成或修改对象类型的结构。
- 两者结合是TypeScript类型编程的核心,能够构建出高度抽象和类型安全的工具类型。
- 理解分布式条件类型和键重映射是应对高级面试题的关键。
- 实际开发中,应优先使用内置工具类型,在它们无法满足需求时,再考虑自定义高级类型。
掌握这些高级类型,不仅能让你在面试中游刃有余,更能显著提升代码的类型表现力和健壮性。同时,优秀的工具能事半功倍,无论是TypeScript的类型系统,还是数据库开发工具。例如,在记录和分享这些复杂的技术点或SQL查询案例时,使用 QueryNote (https://note.dblens.com) 这样的云端笔记工具,可以方便地进行代码高亮、团队协作和知识沉淀,让技术管理更加高效。
通过不断练习和实战,你将能灵活运用条件类型和映射类型,构建出真正强大的TypeScript应用程序。
本文来自博客园,作者:DBLens数据库开发工具,转载请注明原文链接:https://www.cnblogs.com/dblens/p/19554589
浙公网安备 33010602011771号