eagleye

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) => { ... }, {})

 

posted on 2025-06-27 17:17  GoGrid  阅读(439)  评论(0)    收藏  举报

导航