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
Typeis aData.TaggedErrorwhose only field is a human-readablemessage.-
For each validation scenario this module exports two functions:
- A constructor (e.g. {@link wrongValue}, {@link missized}) that builds an
InputErrorwith 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.
- A constructor (e.g. {@link wrongValue}, {@link missized}) that builds an
- 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.
regExpDescriptoris 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/maxIncludedcontrol whether the corresponding bound is inclusive.offsetis added tomin,maxandactualonly 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. namedefaults 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>orstring. - 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>orstring. - 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, otherwiseResult.failurewith 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>