引言
TypeScript作为JavaScript的超集,不仅提供了静态类型检查,还拥有一个强大而灵活的类型系统。掌握高级类型特性,能够让我们编写出更加类型安全、可维护性更高的代码。本文将深入探讨TypeScript的8大高级类型特性,帮助你充分发挥类型系统的威力。
泛型类型
1. 基础泛型
泛型是TypeScript类型系统的核心,它允许我们编写可复用的组件和函数。
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 使用示例
const num = identity<number>(42);
const str = identity<string>('hello');
// 类型推断
const inferred = identity('world'); // 自动推断为string
2. 泛型约束
限制泛型的类型范围,确保类型安全。
// 约束泛型必须有length属性
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): number {
console.log(arg.length);
return arg.length;
}
logLength('hello'); // 5
logLength([1, 2, 3]); // 3
logLength({ length: 10, value: 'test' }); // 10
3. 泛型接口和类
// 泛型接口
interface Box<T> {
value: T;
getValue(): T;
setValue(value: T): void;
}
// 泛型类
class Storage<T> implements Box<T> {
private value: T;
constructor(initialValue: T) {
this.value = initialValue;
}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
// 使用示例
const stringStorage = new Storage<string>('initial');
const numberStorage = new Storage<number>(100);
条件类型
4. 基础条件类型
条件类型类似于三元表达式,根据类型条件选择不同的类型。
// 基础条件类型
type IsString<T> = T extends string ? true : false;
type Test1 = IsString<string>; // true
type Test2 = IsString<number>; // false
// 实用示例:提取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser(): string {
return 'user';
}
type UserReturn = ReturnType<typeof getUser>; // string
5. 分布式条件类型
当条件类型作用于联合类型时,会自动分发到每个成员。
type ToArray<T> = T extends any ? T[] : never;
type StrArrOrNumArr = ToArray<string | number>;
// 等同于 string[] | number[]
// 过滤联合类型
type Filter<T, U> = T extends U ? T : never;
type Strings = Filter<string | number | boolean, string>;
// 等同于 string
映射类型
6. 基础映射类型
映射类型可以基于旧类型创建新类型。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface User {
id: number;
name: string;
email: string;
}
type ReadonlyUser = Readonly<User>;
type PartialUser = Partial<User>;
// 使用示例
const user: ReadonlyUser = {
id: 1,
name: 'John',
email: 'john@example.com'
};
// user.id = 2; // 错误:只读属性
7. 高级映射类型
// 可选转必选
type Required<T> = {
[P in keyof T]-?: T[P];
};
// 只读转可写
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
// 提取特定类型的属性
type PickByType<T, U> = {
[P in keyof T as T[P] extends U ? P : never]: T[P];
};
interface Product {
id: number;
name: string;
price: number;
description: string;
}
type StringProperties = PickByType<Product, string>;
// { name: string; description: string }
模板字面量类型
8. 字符串操作类型
TypeScript 4.1引入了模板字面量类型,可以对字符串类型进行操作。
// 基础模板字面量类型
type Greeting = 'hello' | 'hi';
type Target = 'world' | 'everyone';
type Message = `${Greeting} ${Target}`;
// 'hello world' | 'hello everyone' | 'hi world' | 'hi everyone'
// 实用示例:事件名称类型
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<'click'>; // 'onClick'
type SubmitEvent = EventName<'submit'>; // 'onSubmit'
9. 字符串工具类型
// 类型转换
type Uppercase<T extends string> = intrinsic;
type Lowercase<T extends string> = intrinsic;
type Capitalize<T extends string> = intrinsic;
type Uncapitalize<T extends string> = intrinsic;
// 使用示例
type Upper = Uppercase<'hello'>; // 'HELLO'
type Lower = Lowercase<'WORLD'>; // 'world'
type Cap = Capitalize<'hello'>; // 'Hello'
type Uncap = Uncapitalize<'Hello'>; // 'hello'
索引访问类型
10. 深度类型访问
使用索引访问类型可以深入访问嵌套的类型结构。
interface Config {
database: {
host: string;
port: number;
credentials: {
username: string;
password: string;
};
};
}
// 访问嵌套类型
type DbConfig = Config['database'];
type HostType = Config['database']['host']; // string
type Credentials = Config['database']['credentials'];
// 实用示例:获取数组元素类型
type ArrayElement<T extends readonly any[]> = T extends readonly (infer U)[] ? U : never;
type Numbers = number[];
type Num = ArrayElement<Numbers>; // number
递归类型
11. 递归类型定义
递归类型可以定义自引用的数据结构。
// 链表节点
type ListNode<T> = {
value: T;
next: ListNode<T> | null;
};
// 二叉树节点
type TreeNode<T> = {
value: T;
left: TreeNode<T> | null;
right: TreeNode<T> | null;
};
// 使用示例
const numberNode: ListNode<number> = {
value: 1,
next: {
value: 2,
next: null
}
};
12. 递归类型工具
// 深度只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
// 深度可选
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
interface NestedConfig {
level1: {
level2: {
value: string;
};
};
}
type ReadonlyNested = DeepReadonly<NestedConfig>;
类型推断与守卫
13. 类型推断
使用infer关键字在条件类型中推断类型。
// 推解数组类型
type UnpackedArray<T> = T extends (infer U)[] ? U : T;
type Arr = number[];
type Item = UnpackedArray<Arr>; // number
// 推解Promise类型
type UnpackedPromise<T> = T extends Promise<infer U> ? U : T;
type PromiseString = Promise<string>;
type String = UnpackedPromise<PromiseString>; // string
// 推解函数参数类型
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
function greet(name: string, age: number): void {
console.log(`Hello ${name}, you are ${age}`);
}
type GreetParams = Parameters<typeof greet>; // [string, number]
14. 类型守卫
类型守卫可以在运行时缩小类型范围。
// typeof类型守卫
function processValue(value: string | number) {
if (typeof value === 'string') {
console.log(value.toUpperCase()); // value是string
} else {
console.log(value.toFixed(2)); // value是number
}
}
// instanceof类型守卫
class Dog {
bark() { console.log('Woof!'); }
}
class Cat {
meow() { console.log('Meow!'); }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
// 自定义类型守卫
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
function isFish(pet: Bird | Fish): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function move(pet: Bird | Fish) {
if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}
}
实用类型组合
15. 构建复杂类型
组合多种类型特性构建实用的复杂类型。
// 不可变状态类型
type ImmutableState<T> = DeepReadonly<{
[K in keyof T]: T[K];
}>;
// API响应类型
type ApiResponse<T, E = Error> = {
success: boolean;
data?: T;
error?: E;
};
// 分页数据类型
type PaginatedData<T> = {
items: T[];
total: number;
page: number;
pageSize: number;
hasMore: boolean;
};
// 使用示例
interface User {
id: number;
name: string;
email: string;
}
type UserResponse = ApiResponse<User>;
type UserListResponse = ApiResponse<PaginatedData<User>>;
// 函数重载类型
type Overloaded<T> = {
(value: string): T;
(value: number): T;
(value: boolean): T;
};
// 工厂函数类型
type Factory<T> = new (...args: any[]) => T;
class Product {
constructor(public name: string) {}
}
type ProductFactory = Factory<Product>;
总结
TypeScript的高级类型系统为我们提供了强大的类型安全能力:
核心特性
- 泛型:编写可复用的类型安全代码
- 条件类型:根据类型条件动态选择类型
- 映射类型:基于现有类型创建新类型
- 模板字面量类型:操作字符串类型
- 递归类型:定义复杂的数据结构
- 类型推断:自动推断和提取类型信息
最佳实践
- 渐进式采用:从简单类型开始,逐步使用高级特性
- 保持可读性:复杂的类型应该有清晰的注释
- 避免过度设计:不要为了使用高级特性而使用
- 类型复用:将常用类型提取为可复用的类型别名
学习路径
- 掌握基础类型和接口
- 学习泛型和泛型约束
- 理解条件类型和映射类型
- 探索模板字面量类型
- 实践类型推断和类型守卫
- 组合多种特性构建复杂类型
掌握TypeScript高级类型系统,将帮助你编写出更加健壮、可维护的代码。类型安全不仅能在编译时捕获错误,还能提供更好的IDE支持和代码提示。开始在你的项目中应用这些高级特性吧!
本文首发于掘金,欢迎关注我的专栏获取更多前端技术干货!