Home Reference Source Test

src/predicates/property.ts

import { and } from './and';
import { Failure, Predicate, Result, Success } from './Predicate';

/**
 * @desc Ensures that the `property` of the `value` meets the `predicates`
 *
 * @example
 * import { ensure, isGreaterThan, property, TinyType } from 'tiny-types';
 *
 * class Name extends TinyType {
 *     constructor(public readonly value: string) {
 *         super();
 *         ensure('Name', value, property('length', isGreaterThan(3)));
 *     }
 * }
 *
 * @returns {Predicate<T>}
 */
export function property<T, K extends keyof T>(propertyName: K, ...predicates: Array<Predicate<T[K]>>): Predicate<T> {
    return new HaveProperty<T, K>(propertyName, and(...predicates));
}

/** @access private */
class HaveProperty<T, K extends keyof T> extends Predicate<T> {

    constructor(private readonly propertyName: K, private readonly predicate: Predicate<T[K]>) {
        super();
    }

    /** @override */
    check(value: T): Result<T> {
        const result = this.predicate.check(value[this.propertyName]);

        return result instanceof Failure
            ? new Failure(value, `have a property "${ String(this.propertyName) }" that ${ result.description }`
                .replaceAll(/\bbe\b/gi, 'is')
                .replaceAll(/\beither is\b/gi, 'is either'),
            )
            : new Success(value);
    }
}