eagleye

TypeScript数组之filter函数企业级实用教程

TypeScript数组之filter函数企业级实用教程

一、基础语法与核心特性

1. 定义

filter()是数组的高阶函数,用于根据条件筛选元素,返回一个包含所有符合条件元素的新数组(原数组不变)。

2. 语法

const newArray = array.filter(

callback: (value: T, index: number, array: T[]) => boolean,

thisArg?: any

): T[]

参数

§ callback:必选,接收三个参数(当前元素value、索引index、原数组array),返回boolean(true保留元素,false过滤)。

§ thisArg:可选,执行回调时的this指向。

核心特性

§ 纯函数属性:不修改原数组,返回新数组(长度 ≤ 原数组)。

§ 类型安全TypeScript自动推断新数组类型(与原数组一致)。

二、企业级核心应用场景

①1.数据筛选与过滤

场景:从后端返回的原始数据中,筛选符合业务条件的记录(如状态、权限、搜索关键词)。

示例:筛选未删除且角色为“管理员”的用户

interface User { id: number; name: string; role: string; isDeleted: boolean; }

const users: User[] = [

{ id: 1, name: 'Alice', role: 'admin', isDeleted: false },

{ id: 2, name: 'Bob', role: 'user', isDeleted: false },

{ id: 3, name: 'Charlie', role: 'admin', isDeleted: true }

];

// 筛选条件:未删除(!isDeleted)且角色为管理员(role === 'admin')

const activeAdmins = users.filter(user => !user.isDeleted && user.role === 'admin');

// 结果: [{ id: 1, name: 'Alice', ... }]

企业级价值:替代冗长的for循环+if判断,一行代码完成多条件筛选。

②2.数组去重(配合indexOf/includes)

场景:去除数组中的重复元素(适用于简单类型数组)。

示例:筛选唯一ID的用户

const ids = [1, 2, 2, 3, 3, 3];

const uniqueIds = ids.filter((id, index, self) => self.indexOf(id) === index);

// 结果: [1, 2, 3]

注意:复杂对象去重需用Map或Set(见场景5),此方法仅适用于基本类型。

③3.权限控制与数据脱敏

场景:根据用户权限筛选可展示的数据(如隐藏敏感字段或无权限的记录)。

示例:仅展示用户有权限访问的菜单

interface Menu { id: number; name: string; requiredRole: string[]; }

const menus: Menu[] = [

{ id: 1, name: '仪表盘', requiredRole: ['user', 'admin'] },

{ id: 2, name: '权限管理', requiredRole: ['admin'] }

];

const userRole = 'user'; // 当前用户角色

const accessibleMenus = menus.filter(menu =>

menu.requiredRole.includes(userRole)

);

// 结果: [{ id: 1, name: '仪表盘', ... }]

④4.空值/无效数据过滤

场景:清洗数组中的null、undefined、空字符串等无效数据。

示例:过滤掉未定义的用户名称

const userNames: (string | undefined)[] = ['Alice', undefined, 'Bob', null, ''];

const validNames = userNames.filter((name): name is string =>

typeof name === 'string' && name.trim() !== ''

);

// 结果: ['Alice', 'Bob'](类型收窄为string[])

TypeScript技巧:使用类型谓词name is string)将返回值类型从(string | undefined)[]收窄为string[],避免后续类型错误。

⑤5.复杂对象去重(基于唯一键)

场景:根据对象的唯一键(如id)去重,适用于接口返回的列表数据。

示例

const usersWithDuplicates = [

{ id: 1, name: 'Alice' },

{ id: 1, name: 'Alice' }, // 重复id

{ id: 2, name: 'Bob' }

];

const uniqueUsers = usersWithDuplicates.filter(

(user, index, self) => self.findIndex(u => u.id === user.id) === index

);

// 结果: [{ id: 1, ... }, { id: 2, ... }]

三、TypeScript类型安全实践

⑥1.使用类型谓词收窄类型

当筛选联合类型数组(如(string | number)[])时,通过类型谓词明确返回值类型:

const mixedArray: (string | number)[] = [1, 'a', 2, 'b'];

// 筛选出所有字符串,并收窄类型为string[]

const strings = mixedArray.filter((item): item is string => typeof item === 'string');

⑦2.接口/类型别名约束筛选条件

interface Product { id: number; price: number; inStock: boolean; }

type InStockProduct = Product & { inStock: true }; // 仅包含库存商品的类型

const products: Product[] = [{ id: 1, price: 100, inStock: true }];

// 筛选库存商品,并通过类型断言确保类型安全

const stockProducts = products.filter(p => p.inStock) as InStockProduct[];

四、企业级避坑指南

⑧1.混淆filter与map的返回值

❌ 错误:试图在filter中转换数据(应使用map)

const numbers = [1, 2, 3];

const doubled = numbers.filter(num => num * 2); // 结果: [1, 2, 3](因num*2始终为true)

✅ 正确:先筛选后转换(filter+map链式调用)

const doubledEvens = numbers.filter(num => num % 2 === 0).map(num => num * 2); // [4]

⑨2.忽略回调函数的返回值类型

❌ 错误:回调返回非布尔值(TypeScript会报错,但需显式处理)

const filtered = [1, 2, 3].filter(num => num > 2 ? num : false); // 类型错误!

✅ 正确:确保回调始终返回boolean

const filtered = [1, 2, 3].filter(num => num > 2); // 正确返回boolean

⑩3.大型数组的性能问题
  • 问题filter会遍历整个数组,数据量>10万时可能阻塞主线程。
  • 优化方案// 方案1:分片处理(避免长任务阻塞)

const chunkFilter = async (arr: number[], chunkSize = 1000) => {

const result = [];

for (let i = 0; i < arr.length; i += chunkSize) {

const chunk = arr.slice(i, i + chunkSize);

result.push(...chunk.filter(num => num > 100));

await new Promise(res => setTimeout(res, 0)); // 让出主线程

}

return result;

};

// 方案2:Web Worker处理(完全不阻塞主线程)

五、常见问题与解决方案

问题

原因

企业级解决方案

筛选后数组类型未收窄

联合类型数组筛选后类型仍为原类型

使用类型谓词(item is Type)或类型断言

复杂对象去重效率低

findIndex嵌套遍历导致O(n²)复杂度

改用Map缓存已处理ID:new Map(arr.map(item => [item.id, item])).values()

误将filter用于转换数据

混淆filter(筛选)与map(转换)

遵循“先筛选后转换”原则,链式调用filter().map()

六、总结

filter是企业开发中数据清洗和条件筛选的核心工具,其价值在于:

1. 声明式语法:一行代码替代多行for+if,可读性提升60%+。

2. 类型安全:结合TypeScript类型谓词,避免运行时类型错误。

3. 纯函数特性:不修改原数组,符合函数式编程范式,降低副作用风险。

企业级口诀“筛选用filter,返回布尔值,纯函数无副作用,类型收窄更安全”。

最佳实践:与map、reduce链式调用(如filter().map().reduce()),实现“筛选→转换→聚合”的完整数据处理流程。

 

posted on 2025-08-23 13:04  GoGrid  阅读(94)  评论(0)    收藏  举报

导航