export interface Predicate { (param: T): boolean; } export interface Callable { (...xs: any): any; } export interface Localized { locale: string; } export type FilterCriteriaRecord > = { [K in keyof T]?: T[K] | Predicate; } export type FilterCriteriaRecordValue > = FilterCriteriaRecord[keyof T] export type FilterCriteriaRecordField > = [ keyof T, FilterCriteriaRecordValue ]; export function isCallableCriteriaRecordValue (value: FilterCriteriaRecordValue): value is Predicate { return typeof value === 'function'; } export function filterByCriteriaRecordField (target: T) { return function ([key, value]: FilterCriteriaRecordField): boolean { return isCallableCriteriaRecordValue(value) ? value(target?.[key]) : target?.[key] === value; }; } export function filterByCriteriaRecord (criteria: FilterCriteriaRecord) { return function (target: T): boolean { return Object.entries>(criteria) .every( filterByCriteriaRecordField(target) as Callable ); }; } export function filterArrayByCriteriaRecord (array: T[], criteria?: FilterCriteriaRecord): T[] { return criteria ? array?.filter(filterByCriteriaRecord(criteria)) : array; }