TypeScript数组之filter函数企业级实用教程
TypeScript数组之filter函数企业级实用教程
一、基础语法与核心特性
1. 定义
filter()是数组的高阶函数,用于根据条件筛选元素,返回一个包含所有符合条件元素的新数组(原数组不变)。
2. 语法
const newArray = array.filter(
callback: (value: T, index: number, array: T[]) => boolean,
thisArg?: any
): T[]
o 参数:
§ callback:必选,接收三个参数(当前元素value、索引index、原数组array),返回boolean(true保留元素,false过滤)。
§ thisArg:可选,执行回调时的this指向。
o 核心特性:
§ 纯函数属性:不修改原数组,返回新数组(长度 ≤ 原数组)。
§ 类型安全: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()),实现“筛选→转换→聚合”的完整数据处理流程。
浙公网安备 33010602011771号