type Predicate<T> = (value: T) => boolean;
const and = <T>(...preds: Predicate<T>[]): Predicate<T> =>
(value) => preds.every(p => p(value));
const or = <T>(...preds: Predicate<T>[]): Predicate<T> =>
(value) => preds.some(p => p(value));
const not = <T>(pred: Predicate<T>): Predicate<T> =>
(value) => !pred(value);
const isEven: Predicate<number> = n => n % 2 === 0;
const isPositive: Predicate<number> = n => n > 0;
const isOddAndPositive = and(not(isEven), isPositive);
console.log(isOddAndPositive(3), isOddAndPositive(-3));