Effect CommunityEC
Effect Community3y ago
4 replies
bigpopakap

Improved Wrapper for Brand.refined with Feedback Opportunity

This is partly an FYI and party an opportunity to gather feedback. I've written this little wrapper around Brand.refined which I think is a little more ergonomic:

export const Brand_refined = <Branded extends B.Brand<string | symbol>>(
    refinements: readonly ((unbranded: B.Brand.Unbranded<Branded>) => E.Either<B.Brand.BrandErrors, unknown>)[],
) => (
    unbranded: B.Brand.Unbranded<Branded>,
): E.Either<B.Brand.BrandErrors, Branded> =>
    pipe(
        unbranded,
        Either_validate(refinements),
        E.bimap(
            errors => B.errors(...errors),
            () => B.nominal<Branded>()(unbranded),
        ),
    );


Which can then be used like:
import * as B from '@effect/data/Brand';
import * as P from '@effect/data/Predicate';
import * as E from '@effect/data/Either';

type PositiveNumber = number & B.Brand<'PositiveNumber'>;

const PositiveNumber = Brand_refined<PositiveNumber>([
    Either_fromPredicate(
        (num) => num > 0,
        constant(B.error(`number must be positive`)),
    ),
]);

E.gen(function* ($) {
  const positive1 = yield* $(PositiveNumber(1));
});


I generally like having this E.Either<B.Brand.BrandErrors, Branded> so that the errors can be caught explicitly
Was this page helpful?