Factory functions for creating custom validators with type safety and validation logic for domain-specific requirements. These functions enable extending envalid with application-specific validation rules.
Creates custom validators with subtype narrowing capabilities, allowing choices array for constraining valid values.
/**
* Creates custom validators with subtype narrowing
* @param parseFn - Function that parses and validates input string
* @returns BaseValidator function that can be used with specs
*/
function makeValidator<BaseT>(
parseFn: (input: string) => BaseT
): BaseValidator<BaseT>;Usage Examples:
import { makeValidator, cleanEnv } from "envalid";
// Create a custom validator for positive integers
const positiveInt = makeValidator((input: string) => {
const parsed = parseInt(input, 10);
if (isNaN(parsed) || parsed <= 0) {
throw new Error("Must be a positive integer");
}
return parsed;
});
// Create a custom validator for comma-separated strings
const csvList = makeValidator((input: string) => {
return input.split(",").map(item => item.trim());
});
// Use custom validators
const env = cleanEnv(process.env, {
MAX_RETRIES: positiveInt({ default: 3 }),
ALLOWED_ORIGINS: csvList(),
WORKER_COUNT: positiveInt({ choices: [1, 2, 4, 8] }),
});Creates validators with exact type output, providing no subtype narrowing where output type is exactly T.
/**
* Creates validators with exact type output
* No subtype narrowing, output type is exactly T
* @param parseFn - Function that parses input string to exact type T
* @returns ExactValidator function for the specified type
*/
function makeExactValidator<T>(
parseFn: (input: string) => T
): ExactValidator<T>;Usage Examples:
import { makeExactValidator, cleanEnv } from "envalid";
// Create exact validator for specific enum values
enum LogLevel {
DEBUG = "debug",
INFO = "info",
WARN = "warn",
ERROR = "error"
}
const logLevel = makeExactValidator<LogLevel>((input: string) => {
if (!Object.values(LogLevel).includes(input as LogLevel)) {
throw new Error(`Invalid log level: ${input}`);
}
return input as LogLevel;
});
// Create exact validator for date objects
const dateValidator = makeExactValidator<Date>((input: string) => {
const date = new Date(input);
if (isNaN(date.getTime())) {
throw new Error("Invalid date format");
}
return date;
});
// Use exact validators
const env = cleanEnv(process.env, {
LOG_LEVEL: logLevel({ default: LogLevel.INFO }),
CREATED_AT: dateValidator(),
});Creates validators for complex/structured data, used for JSON and other structured input formats.
/**
* Creates validators for complex/structured data
* Used for JSON and other structured input formats
* @param parseFn - Function that parses input string to unknown type
* @returns StructuredValidator that can be typed with generics
*/
function makeStructuredValidator(
parseFn: (input: string) => unknown
): StructuredValidator;Usage Examples:
import { makeStructuredValidator, cleanEnv } from "envalid";
// Create validator for YAML-like configuration
const yamlConfig = makeStructuredValidator((input: string) => {
// Simple YAML-like parser (in real usage, use a proper YAML library)
const lines = input.split('\n');
const config: Record<string, any> = {};
for (const line of lines) {
const [key, value] = line.split(':').map(s => s.trim());
if (key && value) {
config[key] = isNaN(Number(value)) ? value : Number(value);
}
}
return config;
});
// Create validator for custom serialized objects
const serializedUser = makeStructuredValidator((input: string) => {
const parts = input.split('|');
if (parts.length !== 3) {
throw new Error("Invalid user format");
}
return {
id: parseInt(parts[0]),
name: parts[1],
email: parts[2]
};
});
interface UserConfig {
id: number;
name: string;
email: string;
}
// Use structured validators
const env = cleanEnv(process.env, {
APP_CONFIG: yamlConfig<Record<string, any>>(),
DEFAULT_USER: serializedUser<UserConfig>(),
});import { makeValidator, cleanEnv } from "envalid";
// Custom validator with multiple validation steps
const securePassword = makeValidator((input: string) => {
if (input.length < 8) {
throw new Error("Password must be at least 8 characters");
}
if (!/[A-Z]/.test(input)) {
throw new Error("Password must contain uppercase letter");
}
if (!/[a-z]/.test(input)) {
throw new Error("Password must contain lowercase letter");
}
if (!/\d/.test(input)) {
throw new Error("Password must contain a number");
}
if (!/[!@#$%^&*]/.test(input)) {
throw new Error("Password must contain special character");
}
return input;
});
const env = cleanEnv(process.env, {
ADMIN_PASSWORD: securePassword(),
});import { makeValidator, cleanEnv } from "envalid";
import { isValidObjectId } from "mongodb";
// Validator that uses external library
const mongoId = makeValidator((input: string) => {
if (!isValidObjectId(input)) {
throw new Error("Invalid MongoDB ObjectId");
}
return input;
});
const env = cleanEnv(process.env, {
USER_ID: mongoId(),
DOCUMENT_ID: mongoId(),
});type BaseValidator<BaseT> = <T extends BaseT = BaseT>(
spec?: Spec<T>
) => ValidatorSpec<T>;
type ExactValidator<T> = (spec?: Spec<T>) => ValidatorSpec<T>;
type StructuredValidator = <T = unknown>(
spec?: Spec<T>
) => ValidatorSpec<T>;
type ValidatorSpec<T> = RequiredValidatorSpec<T> | OptionalValidatorSpec<T>;
interface RequiredValidatorSpec<T> extends Spec<T> {
_parse: (input: string) => T;
}
interface OptionalValidatorSpec<T> extends Spec<T | undefined> {
_parse: (input: string) => T;
}