Skip to main content Link Search Menu Expand Document (external link)

InputError overview

Tagged error type for input-validation failures, paired with constructors that build the error message and assertion helpers that lift those constructors into Result-returning predicates.

Mental model

  • Type is a Data.TaggedError whose only field is a human-readable message.
  • For each validation scenario this module exports two functions:

    • A constructor (e.g. {@link wrongValue}, {@link missized}) that builds an InputError with a pre-formatted message;
    • An assertion (e.g. {@link assertValue}, {@link assertLength}) that returns a curried predicate (input) => Result.Result<input, Type> using that constructor on failure.
  • All name-bearing inputs default the prefix of the message to "value" when omitted.

Common tasks

  • Validate equality: {@link assertValue} (and constructor {@link wrongValue})
  • Validate length: {@link assertLength}, {@link assertMaxLength} (constructors {@link missized}, {@link oversized})
  • Validate range: {@link assertInRange} (constructor {@link outOfBounds})
  • Validate strings: {@link assertStartsWith}, {@link assertMatches}, {@link match}, {@link assertEmpty} (constructors {@link notStartingWith}, {@link notMatching}, {@link notEmpty})

Quickstart

Example (Validate a value)

import { Result, pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

console.log(pipe("admin", MInputError.assertValue({ expected: "admin", name: "role" })))
// Success('admin')

console.log(pipe("user", MInputError.assertValue({ expected: "admin", name: "role" })))
// Failure(InputError("Expected role to be: 'admin'. Actual: 'user'"))

Table of contents


Constructors

missized

Builds an InputError for an array-like value whose length differs from the expected one.

Signature

export declare const missized: ({
  expected,
  actual,
  name
}: {
  readonly expected: number
  readonly actual: number
  readonly name?: string
}) => Type

notEmpty

Builds an InputError for a string that should have been empty.

Signature

export declare const notEmpty: ({ actual, name }: { readonly actual: string; readonly name?: string }) => Type

notMatching

Builds an InputError for a string that does not match a given regular expression.

  • regExpDescriptor is the human-readable description used in the error message (e.g. "a valid email").

Signature

export declare const notMatching: ({
  regExpDescriptor,
  actual,
  name
}: {
  readonly regExpDescriptor: string
  readonly actual: string
  readonly name?: string
}) => Type

notStartingWith

Builds an InputError for a string that does not start with startString.

Signature

export declare const notStartingWith: ({
  startString,
  actual,
  name
}: {
  readonly startString: string
  readonly actual: string
  readonly name?: string
}) => Type

outOfBounds

Builds an InputError for a numeric value that fell outside [min, max].

  • minIncluded / maxIncluded control whether the corresponding bound is inclusive.
  • offset is added to min, max and actual only when formatting the message — it is purely cosmetic and lets callers report bounds in a different unit (e.g. 1-based indexing).

Signature

export declare const outOfBounds: ({
  min,
  max,
  minIncluded,
  maxIncluded,
  offset,
  actual,
  name
}: {
  readonly min: number
  readonly max: number
  readonly minIncluded: boolean
  readonly maxIncluded: boolean
  readonly offset: number
  readonly actual: number
  readonly name?: string
}) => Type

oversized

Builds an InputError for an array-like value whose length exceeds the expected upper bound.

Signature

export declare const oversized: ({
  expected,
  actual,
  name
}: {
  readonly expected: number
  readonly actual: number
  readonly name?: string
}) => Type

wrongValue

Builds an InputError for a value that did not match the expected one.

  • String operands are quoted with single quotes in the message; other primitives are stringified with toString.
  • name defaults to "value" when omitted.

Example (Manual error construction)

import * as MInputError from "@parischap/effect-lib/MInputError"

console.log(MInputError.wrongValue({ expected: "admin", actual: "user", name: "role" }).message)
// "Expected role to be: 'admin'. Actual: 'user'"

Signature

export declare const wrongValue: <T extends MTypes.NonNullablePrimitive>({
  expected,
  actual,
  name
}: {
  readonly expected: T
  readonly actual: T
  readonly name?: string
}) => Type

Models

Type (class)

Tagged error returned by every assertion in this module.

Signature

export declare class Type

Module markers

moduleTag

Module tag.

Signature

export declare const moduleTag: "@parischap/effect-lib/InputError/"

Utils

assertEmpty

Asserts that input is the empty string.

  • Returns a {@link notEmpty} error on failure.

Example (Empty check)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

console.log(pipe("", MInputError.assertEmpty())) // Success('')
console.log(pipe("x", MInputError.assertEmpty())) // Failure(InputError(...))

Signature

export declare const assertEmpty: (params?: {
  readonly name?: string
}) => MTypes.OneArgFunction<string, Result.Result<string, Type>>

assertInRange

Asserts that input lies in the interval [min, max], with each bound inclusive or exclusive according to minIncluded / maxIncluded.

  • Returns an {@link outOfBounds} error on failure.

Example (Range check)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

const isPercentage = MInputError.assertInRange({
  min: 0,
  max: 100,
  minIncluded: true,
  maxIncluded: true,
  offset: 0,
  name: "percentage"
})
console.log(pipe(50, isPercentage)) // Success(50)
console.log(pipe(150, isPercentage)) // Failure(InputError(...))

Signature

export declare const assertInRange: (params: {
  readonly min: number
  readonly max: number
  readonly minIncluded: boolean
  readonly maxIncluded: boolean
  readonly offset: number
  readonly name?: string
}) => MTypes.OneArgFunction<number, Result.Result<number, Type>>

assertLength

Asserts that input.length === expected.

  • Works with any ArrayLike<unknown> or string.
  • Returns a {@link missized} error on failure.

Example (Length check)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

console.log(pipe("abc", MInputError.assertLength({ expected: 3 }))) // Success('abc')
console.log(pipe("abcd", MInputError.assertLength({ expected: 3 }))) // Failure(InputError(...))

Signature

export declare const assertLength: (params: {
  readonly expected: number
  readonly name?: string
}) => <A extends ArrayLike<unknown> | string>(self: A) => Result.Result<A, Type>

assertMatches

Asserts that input matches regExp.

  • Returns the matched input on success, a {@link notMatching} error on failure.

Example (Regex check)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

console.log(pipe("hello", MInputError.assertMatches({ regExp: /^[a-z]+$/, regExpDescriptor: "lowercase letters" })))
// Success('hello')

Signature

export declare const assertMatches: (params: {
  readonly regExp: RegExp
  readonly regExpDescriptor: string
  readonly name?: string
}) => MTypes.OneArgFunction<string, Result.Result<string, Type>>

assertMaxLength

Asserts that input.length <= expected.

  • Works with any ArrayLike<unknown> or string.
  • Returns an {@link oversized} error on failure.

Example (Maximum length check)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

const within10 = MInputError.assertMaxLength({ expected: 10 })
console.log(pipe("hello", within10)) // Success('hello')
console.log(pipe("hello world!", within10)) // Failure(InputError(...))

Signature

export declare const assertMaxLength: (params: {
  readonly expected: number
  readonly name?: string
}) => <A extends ArrayLike<unknown> | string>(self: A) => Result.Result<A, Type>

assertStartsWith

Asserts that input starts with startString.

  • Returns a {@link notStartingWith} error on failure.

Example (Prefix check)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

console.log(pipe("hello world", MInputError.assertStartsWith({ startString: "hello" })))
// Success('hello world')

Signature

export declare const assertStartsWith: (params: {
  readonly startString: string
  readonly name?: string
}) => MTypes.OneArgFunction<string, Result.Result<string, Type>>

assertValue

Asserts that input === expected (using strict equality).

  • Returns Result.success(input) when the equality holds, otherwise Result.failure with a {@link wrongValue} error.

Example (Equality check)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

const isAdmin = MInputError.assertValue({ expected: "admin", name: "role" })

console.log(pipe("admin", isAdmin)) // Success('admin')
console.log(pipe("user", isAdmin)) // Failure(InputError(...))

Signature

export declare const assertValue: <T extends MTypes.NonNullablePrimitive>(params: {
  readonly expected: NoInfer<T>
  readonly name?: string
}) => MTypes.OneArgFunction<T, Result.Result<T, Type>>

match

Returns the substring of input matching regExp. Returns a {@link notMatching} error when input does not match.

  • Differs from {@link assertMatches} in that the success value is the matched substring, not the whole input.

Example (Extract first match)

import { pipe } from "effect"
import * as MInputError from "@parischap/effect-lib/MInputError"

console.log(pipe("abc123", MInputError.match({ regExp: /\d+/, regExpDescriptor: "digits" })))
// Success('123')

Signature

export declare const match: (params: {
  readonly regExp: RegExp
  readonly regExpDescriptor: string
  readonly name?: string
}) => (self: string) => Result.Result<string, Type>