Return type of applyTo() can be limited to enum-like type; enum and union.
This is useful for TypeScript.
export function enumeration<E = never>(rules: RulesForEnumeration): EnumerationSchema<E>;
type RulesForEnumeration = {
map?: string;
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
}Applies schema to value.
If an error occurs, this method calls onError (if specified) or throw ValueSchemaError (otherwise).
See example of 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);
}Maps the specified value to the properties of the input object.
NOTE: This rule is only available in object.
const schemaObject = {
favoriteDrink: vs.enumeration({
map: "favorite_drink",
only: ["tea", "milk", "juice", "coffee"] as const,
}),
};
const input = { // input values
favorite_drink: "tea",
};
assert.deepStrictEqual(
vs.applySchemaObject(schemaObject, input),
{favoriteDrink: "tea"});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);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});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});