TypeScript 高阶函数深度解析:filter、map、reduce
TypeScript 高阶函数深度解析:filter、map、reduce
在 TypeScript 中,filter、map和reduce是数组的核心高阶函数(Higher-Order Functions),它们是函数式编程的基石。这些函数通过接受函数作为参数、返回新数据结构(不修改原数组)和声明式语法,提供了高效、类型安全的数据处理方式。本文将从基础概念到企业级实践,全面解析这三个高阶函数的应用与最佳实践。
一、高阶函数核心概念
高阶函数的核心特点:
- 接受函数作为参数:通过传入回调函数定义数据处理逻辑。
- 返回新数据结构:始终返回新数组(或聚合值),保持原数组不可变。
- 声明式编程:关注“做什么”而非“怎么做”,代码更简洁易读。
- 链式调用:支持filter→map→reduce链式组合,构建复杂数据处理管道。
二、filter:数据筛选专家
2.1 基础用法与类型签名
filter用于筛选数组中符合条件的元素,返回新数组。
类型定义:
filter(callback: (value: T, index: number, array: T[]) => boolean, thisArg?: any): T[];
基础示例:
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(n => n % 2 === 0); // [2, 4]
2.2 类型安全筛选
TypeScript 支持类型推断与类型谓词,确保筛选结果的类型安全。
示例:筛选活跃用户:
interface User {
id: number;
name: string;
age: number;
isActive: boolean;
}
const users: User[] = [
{ id: 1, name: "Alice", age: 28, isActive: true },
{ id: 2, name: "Bob", age: 32, isActive: false },
];
// 筛选活跃用户(自动推断类型为 User[])
const activeUsers = users.filter(user => user.isActive);
类型谓词增强筛选:
// 精确筛选高级用户(包含 isPremium 属性)
const premiumUsers = users.filter(isPremiumUser);
function isPremiumUser(user: User): user is User & { isPremium: true } {
return user.age > 30 && user.isActive;
}
2.3 企业级应用场景
2.3.1 API 数据过滤
从 API 响应中筛选有效数据:
async function fetchActiveUsers(): Promise<User[]> {
const response = await fetch('/api/users');
const allUsers: User[] = await response.json();
return allUsers.filter(user => user.isActive); // 仅返回活跃用户
}
2.3.2 表单验证
筛选无效表单字段并提示错误:
interface FormField {
name: string;
value: string;
isValid: boolean;
}
function validateForm(fields: FormField[]): boolean {
const invalidFields = fields.filter(field => !field.isValid);
if (invalidFields.length > 0) {
highlightErrors(invalidFields); // 高亮错误字段
return false;
}
return true;
}
2.3.3 权限控制
检查用户是否拥有特定权限:
enum Permission { Read = 'READ', Write = 'WRITE' }
function hasPermission(user: User, required: Permission): boolean {
return user.permissions.filter(p => p === required).length > 0;
}
三、map:数据转换大师
3.1 基础用法与类型签名
map用于将数组元素转换为新值,返回新数组。
类型定义:
map<U>(callback: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
基础示例:
const numbers = [1, 2, 3];
const squared = numbers.map(n => n * n); // [1, 4, 9]
3.2 类型安全转换
map支持泛型,确保输入输出类型的严格对应。
简单类型转换:
const prices = ["10.99", "20.50"];
const numericPrices = prices.map(parseFloat); // [10.99, 20.5]
复杂对象转换:
const userDtos = users.map(user => ({
id: user.id,
fullName: `${user.firstName} ${user.lastName}`,
status: user.isActive ? 'Active' : 'Inactive'
}));
泛型保持类型:
function mapToIds<T extends { id: number }>(items: T[]): number[] {
return items.map(item => item.id); // 输入 T[] → 输出 number[]
}
3.3 企业级应用场景
3.3.1 API 响应格式化
将接口数据转换为应用内部格式:
interface ApiUser { user_id: number; full_name: string }
interface AppUser { id: number; name: string }
function transformApiUsers(apiUsers: ApiUser[]): AppUser[] {
return apiUsers.map(apiUser => ({
id: apiUser.user_id,
name: apiUser.full_name
}));
}
3.3.2 React 组件列表渲染
动态生成组件列表:
interface Product { id: string; name: string; price: number }
function ProductList({ products }: { products: Product[] }) {
return (
<ul>
{products.map(product => (
<li key={product.id}>
{product.name} - ${product.price.toFixed(2)}
</li>
))}
</ul>
);
}
3.3.3 数据规范化
将扁平数据转换为结构化对象:
const data = [{ category: 'A', value: 10 }, { category: 'A', value: 20 }];
const normalized = data.reduce((acc, item) => {
(acc[item.category] ||= []).push(item.value);
return acc;
}, {} as Record<string, number[]>);
// { A: [10, 20] }
四、reduce:数据聚合神器
4.1 基础用法与类型签名
reduce用于将数组聚合为单个值(或复杂结构)。
类型定义:
reduce<U>(callback: (acc: U, curr: T, index: number, array: T[]) => U, initialValue: U): U;
基础示例:
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, curr) => acc + curr, 0); // 10
4.2 高级聚合模式
4.2.1 对象分组
按属性将数组分组为对象:
const orders = [
{ id: 1, currency: 'USD' },
{ id: 2, currency: 'EUR' },
];
const byCurrency = orders.reduce((acc, order) => {
(acc[order.currency] ||= []).push(order);
return acc;
}, {} as Record<string, typeof orders>);
// { USD: [order1], EUR: [order2] }
4.2.2 复杂统计
计算数组的平均值、最大值等:
const products = [
{ price: 100 }, { price: 200 }, { price: 300 }
];
const stats = products.reduce(
(acc, product) => ({
sum: acc.sum + product.price,
count: acc.count + 1,
max: Math.max(acc.max, product.price)
}),
{ sum: 0, count: 0, max: 0 }
);
// { sum: 600, count: 3, max: 300 }
4.2.3 管道处理
按顺序执行多个操作:
const operations = [
(x: number) => x * 2, // 100 → 200
(x: number) => x + 5, // 200 → 205
(x: number) => x * 0.9 // 205 → 184.5
];
const result = operations.reduce((value, op) => op(value), 100); // 184.5
4.3 企业级应用场景
4.3.1 购物车结算
计算购物车总金额(含折扣):
interface CartItem {
price: number;
quantity: number;
discount?: number; // 0-1 折扣率
}
function calculateCartTotal(items: CartItem[]): number {
return items.reduce((total, item) => {
const discountedPrice = item.price * (1 - (item.discount || 0));
return total + discountedPrice * item.quantity;
}, 0);
}
4.3.2 传感器数据分析
统计传感器读数的平均值、最大值等:
interface SensorReading { value: number; sensorId: string }
function analyzeReadings(readings: SensorReading[]) {
return readings.reduce(
(acc, reading) => {
acc.count++;
acc.sum += reading.value;
acc.bySensor[reading.sensorId] = (acc.bySensor[reading.sensorId] || 0) + 1;
return acc;
},
{ count: 0, sum: 0, bySensor: {} as Record<string, number> }
);
}
4.3.3 状态机实现
通过reduce驱动状态转移:
type State = 'idle' | 'loading' | 'success';
type Action = 'FETCH_START' | 'FETCH_SUCCESS';
const stateMachine = (current: State, action: Action): State => {
const transitions = {
idle: { FETCH_START: 'loading' },
loading: { FETCH_SUCCESS: 'success' }
};
return transitions[current][action] || current;
};
const actions: Action[] = ['FETCH_START', 'FETCH_SUCCESS'];
const finalState = actions.reduce(stateMachine, 'idle'); // 'success'
五、组合应用:数据处理管道
5.1 基础链式调用
通过filter→map→reduce链式处理数据:
const products = [
{ category: 'Electronics', price: 999 },
{ category: 'Furniture', price: 450 },
];
// 获取电子类产品名称(按价格降序)
const result = products
.filter(p => p.category === 'Electronics')
.sort((a, b) => b.price - a.price)
.map(p => p.name); // ['Laptop']
5.2 企业级数据处理管道
复杂业务逻辑的组合应用:
interface Order {
customerId: number;
items: { price: number; quantity: number }[];
status: 'shipped';
orderDate: Date;
}
// 获取 VIP 客户近 30 天已发货订单的总金额
function getVipShippedTotal(orders: Order[], customers: Customer[]): number {
const cutoff = new Date(Date.now() - 30 * 86400000); // 30 天前
return orders
.filter(o => o.status === 'shipped' && o.orderDate >= cutoff) // 筛选已发货且在 30 天内的订单
.map(o => ({ ...o, customer: customers.find(c => c.id === o.customerId) })) // 关联客户信息
.filter(o => o.customer?.tier === 'vip') // 筛选 VIP 客户
.reduce((total, o) => {
const orderTotal = o.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
return total + orderTotal;
}, 0); // 计算总金额
}
5.3 性能优化策略
避免多次遍历数组,通过单次reduce完成多任务:
// 优化前(多次遍历)
const expensive = products.filter(p => p.price > 500);
const names = expensive.map(p => p.name);
const total = expensive.reduce((sum, p) => sum + p.price, 0);
// 优化后(单次遍历)
const { names, total } = products.reduce(
(acc, product) => {
if (product.price > 500) {
acc.names.push(product.name);
acc.total += product.price;
}
return acc;
},
{ names: [] as string[], total: 0 }
);
六、TypeScript 高级技巧
6.1 自定义高阶函数类型
定义类型安全的高阶函数:
function typedMap<T, U>(array: T[], mapper: (item: T) => U): U[] {
return array.map(mapper); // 严格类型检查
}
const numbers = [1, 2, 3];
const strings = typedMap(numbers, n => n.toString()); // string[]
6.2 异步数据处理
实现异步filter:
async function asyncFilter<T>(
array: T[],
predicate: (item: T) => Promise<boolean>
): Promise<T[]> {
const results = await Promise.all(array.map(predicate));
return array.filter((_, i) => results[i]);
}
// 使用示例
const activeUsers = await asyncFilter(users, async user => {
const activity = await fetchUserActivity(user.id);
return activity.isActive;
});
6.3 不可变数据处理
通过reduce实现状态不可变更新:
interface State { users: User[] }
function addUser(state: State, newUser: User): State {
return { ...state, users: [...state.users, newUser] }; // 不可变更新
}
function updateUser(state: State, userId: number, changes: Partial<User>): State {
return {
...state,
users: state.users.map(user =>
user.id === userId ? { ...user, ...changes } : user
)
};
}
七、企业级最佳实践
7.1 命名规范
使用清晰的变量名,避免缩写:
// 推荐
const activeUsers = users.filter(user => user.isActive);
const userNames = users.map(user => user.name);
// 避免
const a = users.filter(u => u.active);
const b = users.map(u => u.n);
7.2 错误处理
安全处理可能出错的转换:
function safeMap<T, U>(array: T[], mapper: (item: T) => U): Array<U | Error> {
return array.map(item => {
try {
return mapper(item);
} catch (error) {
return error instanceof Error ? error : new Error(String(error));
}
});
}
// 筛选有效结果
const validResults = safeMap(inputs, riskyOperation).filter(
(res): res is U => !(res instanceof Error)
);
7.3 性能监控
记录函数执行时间,优化性能瓶颈:
function withPerfLogging<T, U>(fn: (input: T[]) => U[], name: string) {
return (input: T[]) => {
const start = performance.now();
const result = fn(input);
console.log(`${name} executed in ${(performance.now() - start).toFixed(2)}ms`);
return result;
};
}
// 使用
const processUsers = withPerfLogging(
(users) => users.filter(u => u.isActive).map(u => u.name),
'ActiveUserProcessing'
);
八、总结:选择正确的工具
|
场景 |
推荐方法 |
示例 |
|
数据筛选 |
filter |
activeUsers = users.filter(u => u.isActive) |
|
数据转换 |
map |
userNames = users.map(u => u.name) |
|
单一值计算(求和等) |
reduce |
total = orders.reduce((sum, o) => sum + o.total, 0) |
|
多维分组/统计 |
reduce |
grouped = items.reduce((acc, i) => { ... }, {}) |
浙公网安备 33010602011771号