type Categories = { [key: string]: (item: T) => boolean; }; type CategoryReturnType> = { [key in keyof C]: T[]; }; function initCategories>(categories: C): CategoryReturnType { return Object.keys(categories).reduce((map, key) => { map[key] = []; return map; }, {}) as CategoryReturnType; } export function categorize>( arr: T[], categories: C, ): CategoryReturnType { const result = initCategories(categories); const categoryEntries = Object.entries(categories); itemLoop: for (const item of arr) { for (const [category, fn] of categoryEntries) { if (fn(item)) { result[category].push(item); continue itemLoop; } } } return result; }