Skip to content

Validation

Validation: object

Defined in: Core/Validation.ts:42

apply: {<E2, A>(arg): <B, E1>(validation) => Validation<E2 | E1, B>; <E1, E2, A, E3>(arg, options): <B>(validation) => Validation<E3, B>; }

Applies a function wrapped in a Validation to a value wrapped in a Validation. Accumulates errors from both sides if both fail, using optional combineErrors or default concatenation.

<E2, A>(arg): <B, E1>(validation) => Validation<E2 | E1, B>

E2 = never

A = unknown

Validation<E2, A>

<B, E1>(validation) => Validation<E2 | E1, B>

<E1, E2, A, E3>(arg, options): <B>(validation) => Validation<E3, B>

E1

E2

A

E3

Validation<E2, A>

(e1, e2) => NonEmptyArr<E3>

<B>(validation) => Validation<E3, B>

Validation.struct to combine record validations.

const add = (a: number) => (b: number) => a + b;
pipe(
  Validation.make.passed(add),
  Validation.apply(Validation.make.passed(5)),
  Validation.apply(Validation.make.passed(3))
); // Passed(8)

pipe(
  Validation.make.passed(add),
  Validation.apply(Validation.make.failed<string>("bad a")),
  Validation.apply(Validation.make.failed<string>("bad b"))
); // Failed(["bad a", "bad b"])

// Custom error combination:
pipe(
  Validation.make.passed(add),
  Validation.apply(Validation.make.failed("err"), {
    combineErrors: (e1, e2) => [...e1, ...e2],
  })
);

from: object

Maybe: <E>(onNone) => <A>(maybe) => Validation<E, A>

Creates a Validation from a Maybe. If the Maybe is None, returns Failed with the error from onNone. Otherwise, returns Passed.

E

() => E

<A>(maybe) => Validation<E, A>

pipe(Maybe.make.none(), Validation.from.Maybe(() => "is none")); // Failed(["is none"])
pipe(Maybe.make.some(42), Validation.from.Maybe(() => "is none")); // Passed(42)

nullable: <E>(onNull) => <A>(value) => Validation<E, NonNullable<A>>

Creates a Validation from a nullable value. If the value is null or undefined, returns Failed with the error from onNull. Otherwise, returns Passed.

E

() => E

<A>(value) => Validation<E, NonNullable<A>>

pipe(null, Validation.from.nullable(() => "is null")); // Failed(["is null"])
pipe(42, Validation.from.nullable(() => "is null"));   // Passed(42)

Predicate: {<A, B, E>(refinement, onFalse): (value) => Validation<E, B>; <A, E>(predicate, onFalse): (value) => Validation<E, A>; }

Creates a Validation from a predicate applied to a value. Returns Passed if the predicate passes, Failed from onFalse otherwise.

<A, B, E>(refinement, onFalse): (value) => Validation<E, B>

A

B

E

(value) => value is B

(value) => E

(value) => Validation<E, B>

<A, E>(predicate, onFalse): (value) => Validation<E, A>

A

E

(value) => boolean

(value) => E

(value) => Validation<E, A>

const validateName = Validation.from.Predicate(
  (s: string) => s.length > 0,
  () => "Name is required"
);

validateName("Alice"); // Passed("Alice")
validateName("");      // Failed(["Name is required"])

Result: <E, A>(result) => Validation<E, A>

Converts a Result to a Validation. Ok becomes Passed; Err(e) becomes Failed([e]).

Useful when bridging from error-short-circuiting Result pipelines into error-accumulating Validation pipelines.

E

A

Result<E, A>

Validation<E, A>

Validation.from.Result(Result.make.ok(42));       // Passed(42)
Validation.from.Result(Result.make.err("bad"));   // Failed(["bad"])

getOrElse: <B>(fallback) => <A, E>(validation) => B | A

Returns the success value or a default value if the Validation is failed. The default can be a different type, widening the result to A | B.

B

() => B

<A, E>(validation) => B | A

Validation.match to handle both the passed and failed cases.

pipe(Validation.make.passed(5), Validation.getOrElse(() => 0)); // 5
pipe(Validation.make.failed("oops"), Validation.getOrElse(() => 0)); // 0
pipe(Validation.make.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null

is: object

failed: <E, A>(validation) => validation is Failed<E> = isFailed

Type guard that checks if a Validation is failed.

E

A

Validation<E, A>

validation is Failed<E>

Validation.is.passed to check if a Validation is passed.

const v = Validation.make.failed("invalid");
if (Validation.is.failed(v)) {
  console.log(v.errors); // ["invalid"]
}

passed: <E, A>(validation) => validation is Passed<A> = isPassed

Type guard that checks if a Validation is passed.

E

A

Validation<E, A>

validation is Passed<A>

Validation.is.failed to check if a Validation is failed.

const v = Validation.make.passed(42);
if (Validation.is.passed(v)) {
  console.log(v.value); // 42
}

keyed: object

getErrors: <T>(keyed) => Maybe<KeyedErrors<{ [K in string | number | symbol]: T[K] extends Validation<unknown, A> ? A : never }, T[keyof T] extends Validation<E, unknown> ? E : never>>

Extracts keyed field errors if any field failed. Symmetrical to getPassed: returns Some(errors) when there are failures, or None if every field passed.

T extends Record<string, Validation<unknown, unknown>>

T

Maybe<KeyedErrors<{ [K in string | number | symbol]: T[K] extends Validation<unknown, A> ? A : never }, T[keyof T] extends Validation<E, unknown> ? E : never>>

Validation.keyed.getPassed to extract keyed values when all fields pass.

const errors = Validation.keyed.getErrors(results);
// Some({ name: ["Name required"] }) or None

getPassed: <T, E>(keyed) => Maybe<T>

Extracts all validated field values if every field passed. Returns Some(data) if all passed, None if any field failed.

T extends Record<string, unknown>

E

{ readonly [K in string | number | symbol]: Validation<E, T[K]> }

Maybe<T>

Validation.keyed.getErrors to extract keyed field errors when failures occur.

const passed = Validation.keyed.getPassed(results);
// Some({ name: "Alice", age: 30 }) or None

is: object

failed: <T, E>(keyed) => boolean

Checks if at least one keyed field is Failed.

T extends Record<string, unknown>

E

{ readonly [K in string | number | symbol]: Validation<E, T[K]> }

boolean

Validation.keyed.is.passed to check if all keyed fields passed.

if (Validation.keyed.is.failed(results)) {
  console.log("Validation errors occurred");
}

passed: <T, E>(keyed) => keyed is { readonly [K in string | number | symbol]: Passed<T[K]> }

Type guard checking if every keyed field is Passed.

T extends Record<string, unknown>

E

{ readonly [K in string | number | symbol]: Validation<E, T[K]> }

keyed is { readonly [K in string | number | symbol]: Passed<T[K]> }

Validation.keyed.is.failed to check if any keyed field failed.

if (Validation.keyed.is.passed(results)) {
  // results.name is Passed<string>, results.age is Passed<number>
}

make: <T, E>(validators) => (input) => KeyedResult<T, E>

Creates a keyed validator function from a schema of field validators. Evaluates each validator against its corresponding field in the input object, returning a record where every key holds its own Validation outcome.

T extends Record<string, unknown>

E = unknown

{ readonly [K in string | number | symbol]: (val: T[K]) => Validation<E, T[K]> }

(input) => KeyedResult<T, E>

const validateUser = Validation.keyed.make({
  name: (s: string) => s.length > 0 ? Validation.make.passed(s) : Validation.make.failed("Name required"),
  age: (n: number) => n >= 18 ? Validation.make.passed(n) : Validation.make.failed("Must be 18+"),
});

const result = validateUser({ name: "", age: 16 });
// { name: Failed(["Name required"]), age: Failed(["Must be 18+"]) }

make: object

failed: <E>(error) => Failed<E> = makeFailed

Creates a failed Validation from a single error.

E

E

Failed<E>

Validation.make.failed("Invalid input");

failedAll: <E>(errors) => Failed<E> = makeFailedAll

Creates a failed Validation from multiple errors.

E

NonEmptyArr<E>

Failed<E>

Validation.make.failedAll(["Invalid input"]);

passed: <A>(value) => Passed<A> = makePassed

Wraps a value in a passed Validation.

A

A

Passed<A>

Validation.make.passed(42); // Passed(42)

map: <A, B>(transform) => <E>(validation) => Validation<E, B>

Transforms the success value inside a Validation.

A

B

(value) => B

<E>(validation) => Validation<E, B>

pipe(Validation.make.passed(5), Validation.map(n => n * 2)); // Passed(10)
pipe(Validation.make.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])

mapError: <E, F>(transform) => <A>(validation) => Validation<F, A>

Transforms the error list inside a Validation.

E

F

(error) => F

<A>(validation) => Validation<F, A>

Validation.map to transform the success value.

pipe(Validation.make.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])

match: <E, A, B>(cases) => (validation) => B

Pattern matches on a Validation, returning the result of the matching case.

E

A

B

(errors) => B

(value) => B

(validation) => B

Validation.getOrElse to extract the success value with a default fallback.

pipe(
  validation,
  Validation.match({
    passed: value => `Got ${value}`,
    failed: errors => `Failed: ${errors.join(", ")}`
  })
);

recover: <E1, B, E2>(fallback) => <A>(validation) => Validation<E2, B | A>

Recovers from a Failed state by providing a fallback Validation. The fallback receives the accumulated error list so callers can inspect which errors occurred. The fallback can produce a different success type or resolve with a different error type.

E1

B

E2 = never

(errors) => Validation<E2, B>

<A>(validation) => Validation<E2, B | A>

Validation.recoverUnless to conditionally recover based on accumulated errors.

recoverUnless: <E1, B, E2>(isBlocked, fallback) => <A>(validation) => Validation<E1 | E2, B | A>

Recovers from a Failed state unless isBlocked returns true for any of the accumulated errors. The fallback can produce a different success type, widening the result to Validation<E1 | E2, A | B>.

E1

B

E2 = never

(error) => boolean

(errors) => Validation<E2, B>

<A>(validation) => Validation<E1 | E2, B | A>

Validation.recover for unconditional error recovery.

pipe(
  Validation.make.failed("field-error"),
  Validation.recoverUnless(e => e === "fatal", () => Validation.make.passed(0))
); // Passed(0)

struct: <T>(fields) => Validation<T[keyof T] extends Validation<E, unknown> ? E : never, { [K in string | number | symbol]: T[K] extends Validation<unknown, A> ? A : never }>

Combines a record of Validations into a single Validation of a record. Accumulates all failed branches’ errors.

T extends Record<string, Validation<unknown, unknown>>

T

Validation<T[keyof T] extends Validation<E, unknown> ? E : never, { [K in string | number | symbol]: T[K] extends Validation<unknown, A> ? A : never }>

Validation.struct({
  name: Validation.make.passed("Alice"),
  age: Validation.make.passed(30)
}); // Passed({ name: "Alice", age: 30 })

Validation.struct({
  name: Validation.make.failed("Name required"),
  age: Validation.make.failed("Age must be >= 0")
}); // Failed(["Name required", "Age must be >= 0"])

tap: <A>(sideEffect) => <E>(validation) => Validation<E, A>

Executes a side effect on the success value without changing the Validation.

A

(value) => void

<E>(validation) => Validation<E, A>

Validation.tapError to perform a side effect on accumulated errors.

pipe(
  Validation.make.passed(5),
  Validation.tap(n => console.log("Value:", n)),
  Validation.map(n => n * 2)
);

tapError: <E>(sideEffect) => <A>(validation) => Validation<E, A>

Executes a side effect on the accumulated errors without changing the Validation. Useful for logging or reporting validation failures.

E

(errors) => void

<A>(validation) => Validation<E, A>

Validation.tap to perform a side effect on the success value.

pipe(
  Validation.make.failed("Name required"),
  Validation.tapError(errors => console.error("validation failed:", errors)),
  Validation.map(toUser)
);

to: object

Maybe: <E, A>(validation) => Maybe<A>

Converts a Validation to a Maybe. Passed becomes Some; Failed becomes None (errors are discarded).

E

A

Validation<E, A>

Maybe<A>

Validation.to.Maybe(Validation.make.passed(42));       // Some(42)
Validation.to.Maybe(Validation.make.failed("bad"));  // None

Result: {<E1, E2, A>(combineErrors): (validation) => Result<E2, A>; <E, A>(validation): Result<NonEmptyArr<E>, A>; } = toResult

Converts a Validation to a Result. Passed becomes Ok. Direct call converts Failed to Err with accumulated error list NonEmptyArr<E>. Curried call converts Failed to Err with combined error E2 via combineErrors.

<E1, E2, A>(combineErrors): (validation) => Result<E2, A>

E1

E2

A

(errors) => E2

(validation) => Result<E2, A>

<E, A>(validation): Result<NonEmptyArr<E>, A>

E

A

Validation<E, A>

Result<NonEmptyArr<E>, A>

Validation.to.Result(Validation.make.passed(42));        // Ok(42)
Validation.to.Result(Validation.make.failed("oops"));  // Err(["oops"])
pipe(Validation.make.failed("oops"), Validation.to.Result(errors => errors.join(", "))); // Err("oops")

tryCatch: <E, A>(fn, options) => Validation<E, A>

Creates a Validation from a synchronous thunk that may throw. Catches any errors and transforms them using the onError function into a Failed validation.

E

A

() => A

(error) => E

Validation<E, A>

const result = Validation.tryCatch(
  () => JSON.parse(rawString),
  { onError: (error) => `Parse error: ${error}` }
);