Skip to main content
Module

x/value_schema/docs/reference/enumeration.md

simple, easy-to-use, and declarative input validator; supports Node.js, TypeScript, Deno, and Bun
Latest
File

enumeration

Return type of applyTo() can be limited to enum-like type; enum and union. This is useful for TypeScript.

ambient declarations

export function enumeration<E = never>(rules: RulesForEnumeration): EnumerationSchema<E>;

type RulesForEnumeration = {
    ifUndefined?: string | null;
    ifEmptyString?: string | null;
    ifNull?: string | null;

    only: E[]; // this is NOT an optional.
}
type ErrorHandler = (err: ValueSchemaError) => E | null | never;
interface EnumerationSchema {
    applyTo(value: unknown, onError?: ErrorHandler): E | null
}

applyTo(value[, onError])

Applies schema to value.

If an error occurs, this method calls onError (if specified) or throw ValueSchemaError (otherwise).

See example of only.

rules

only

Accepts only particular values. This is NOT an optional.

// enum version
enum NumberEnum
{
    zero,
    one,
}
enum StringEnum
{
    a = "a",
    b = "b",
}

// should be OK
{
    // pattern 1: enum that contains number elements
    const val: NumberEnum = vs.enumeration({only: [NumberEnum.zero, NumberEnum.one]}).applyTo(1);
    assert.strictEqual(val, 1);
}
{
    // pattern 2: enum that contains only string elements
    const val: StringEnum = vs.enumeration({only: Object.values(StringEnum)}).applyTo("a");
    assert.strictEqual(val, "a");
}

// should cause error
assert.throws(
    () => vs.enumeration({only: Object.values(StringEnum)}).applyTo("c"),
    {name: "ValueSchemaError", rule: vs.RULE.ONLY});
// union version
type NumberUnion = 0 | 1;
type StringUnion = "a" | "b";

// should be OK
{
    // you can use "as const" for union type
    const val: NumberUnion = vs.enumeration({only: [0, 1] as const}).applyTo(1);
    assert.strictEqual(val, 1);
}
{
    // you can also use "<Type>"
    const val: StringEnum = vs.enumeration<StringUnion>({only: ["a", "b"]}).applyTo("a");
    assert.strictEqual(val, "a");
}

// should cause error
assert.throws(
    () => vs.enumeratino({only: ["a", "b"] as const}).applyTo("c"),
    {name: "ValueSchemaError", rule: vs.RULE.ONLY});

CAUTION: In union version, only must be “array of literal union types”, “const-asserted array”, or “array literal with generics”.

type NumberUnion = 0 | 1;

// OK
{
    // array of literal union types
    const val: NumberUnion = vs.enumeration({only: [0, 1] as NumberUnion[]}).applyTo(1);
}
{
    // const-asserted array
    const val: NumberUnion = vs.enumeration({only: [0, 1] as const}).applyTo(1);
}
{
    // array literal with generics
    const val: NumberUnion = vs.enumeration<NumberUnion>({only: [0, 1]}).applyTo(1);
}

// NG (compile error)
{
    // TS2322: Type 'number' is not assignable to type 'NumberUnion'.
    const val: NumberUnion = vs.enumeration({only: [0, 1]}).applyTo(1); // number
}
{
    const only = [0, 1]; // number[]
    const val: NumberUnion = vs.enumeration({only: only}).applyTo(1);
}
{
    const only = [0, 1]; // number[]
    const val: NumberUnion = vs.enumeration<NumberUnion>({only: only}).applyTo(1);
}

ifUndefined

Specifies return value when input value is undefined.

NOTE: {ifUndefined: undefined} is NOT equivalent to {}. The former accepts undefined input value (and keeps it as-is), the latter doesn’t.

enum StringEnum
{
    a = "a",
    b = "b",
}

// should be adjusted
assert.strictEqual(
    vs.enumeration({ifUndefined: StringEnum.a, only: Object.values(StringEnum)}).applyTo(undefined),
    "a");

// should cause error
assert.throws(
    () => vs.enumeration({only: Object.values(StringEnum)}).applyTo(undefined),
    {name: "ValueSchemaError", rule: vs.RULE.UNDEFINED});

// should accept `undefined` value
assert.strictEqual(
    vs.enumeration({ifUndefined: undefined, only: Object.values(StringEnum)}).applyTo(undefined),
    undefined);

ifNull

Specifies return value when input value is null.

enum StringEnum
{
    a = "a",
    b = "b",
}

// should be adjusted
assert.strictEqual(
    vs.enumeration({ifNull: StringEnum.a, only: Object.values(StringEnum)}).applyTo(null),
    "a");

// should cause error
assert.throws(
    () => vs.enumeration({only: Object.values(StringEnum)}).applyTo(null),
    {name: "ValueSchemaError", rule: vs.RULE.NULL});

ifEmptyString

Specifies return value when input value is "".

enum StringEnum
{
    a = "a",
    b = "b",
}

// should be adjusted
assert.strictEqual(
    vs.enumeration({ifEmptyString: StringEnum.a, only: Object.values(StringEnum)}).applyTo(""),
    "a");

// should cause error
assert.throws(
    () => vs.enumeration({only: Object.values(StringEnum)}).applyTo(""),
    {name: "ValueSchemaError", rule: vs.RULE.EMPTY_STRING});