Home Reference Source Test

src/predicates/and.ts

import { isArray } from './isArray';
import { isDefined } from './isDefined';
import { isGreaterThan } from './isGreaterThan';
import { Failure, Predicate, Result, Success } from './Predicate';

/**
 * @desc Ensures that the `value` meets all the provided {@link Predicate}s.
 *
 * @example
 * import { and, ensure, isDefined, isGreaterThan, isInteger, TinyType } from 'tiny-types';
 *
 * class AgeInYears extends TinyType {
 *     constructor(public readonly value: number) {
 *         ensure('AgeInYears', value, and(isDefined(), isInteger(), isGreaterThan(18));
 *     }
 * }
 *
 * @param {...Array<Predicate<T>>} predicates
 * @returns {Predicate<T>}
 */
export function and<T>(...predicates: Array<Predicate<T>>): Predicate<T> {
    return new And<T>(predicates);
}

/** @access private */
class And<T> extends Predicate<T> {

    constructor(private readonly predicates: Array<Predicate<T>>) {
        super();

        const results = [
            _ => isDefined().check(_),
            _ => isArray().check(_),
            _ => isGreaterThan(0).check(_.length),
        ];

        if (results.some(check => check(this.predicates) instanceof Failure)) {
            throw new Error(`Looks like you haven't specified any predicates to check the value against?`);
        }
    }

    /** @override */
    check(value: T): Result<T> {
        for (const predicate of this.predicates) {
            const result = predicate.check(value);
            if (result instanceof Failure) {
                return result;
            }
        }

        return new Success(value);
    }
}