Skip to content

TypeScript Types

Pliant is written in TypeScript and exports comprehensive type definitions.

Core Types

Registry

ts
interface Registry<TData = Record<string, unknown>> {
  // Opaque - use addRules() and evaluateRules()
}

RuleDef

The shape of a validation rule:

ts
interface RuleDef<TData = Record<string, unknown>> {
  /** Validates a value. Returns ErrorDetail on failure, null on success */
  validate(value: unknown, ctx: Context<TData>): ErrorDetail | null;
  
  /** Error code (defaults to rule name) */
  code?: string;
  
  /** Reference to parent rule when using inheritRule() */
  parent?: RuleDef<TData>;
}

Context

Passed to rules during validation:

ts
interface Context<TData = Record<string, unknown>> {
  /** Field name being validated */
  field: string;
  
  /** Additional data (form values, etc.) */
  data?: TData;
}

ErrorDetail

A single validation error:

ts
interface ErrorDetail {
  /** Error code identifying the failure */
  code: string;
  
  /** Additional error data (varies by rule) */
  [key: string]: unknown;
}

ErrorMap

Collection of errors keyed by rule name:

ts
type ErrorMap = Record<string, ErrorDetail>;

ResolvedError

Error with message applied:

ts
interface ResolvedError extends ErrorDetail {
  /** Human-readable message */
  message?: string;
}

ResolvedErrorMap

ts
type ResolvedErrorMap = Record<string, ResolvedError>;

Message Types

MessageCatalog

Maps error codes to messages:

ts
type MessageCatalog = Record<string, string | MessageFunction>;

MessageFunction

Dynamic message generator:

ts
type MessageFunction = (detail: ErrorDetail, ctx?: Context) => string;

MessageResolver

Function returned by createMessageResolver():

ts
type MessageResolver = (code: string, detail: ErrorDetail, ctx?: Context) => string | undefined;

Rule Option Types

RequiredRuleOptions

ts
interface RequiredRuleOptions {
  /** Treat whitespace-only as empty (default: true) */
  trimWhitespace?: boolean;
}

EmailRuleOptions

ts
interface EmailRuleOptions {
  /** Allow empty values (default: true) */
  allowEmpty?: boolean;
}

LengthRuleOptions

ts
interface LengthRuleOptions {
  /** Minimum length */
  min?: number;
  
  /** Maximum length */
  max?: number;
}

MinLengthRuleOptions

ts
interface MinLengthRuleOptions {
  /** Minimum length required */
  min: number;
}

MaxLengthRuleOptions

ts
interface MaxLengthRuleOptions {
  /** Maximum length allowed */
  max: number;
}

RangeRuleOptions

ts
interface RangeRuleOptions {
  /** Minimum value (inclusive) */
  min: number;
  
  /** Maximum value (inclusive) */
  max: number;
}

MinRuleOptions

ts
interface MinRuleOptions {
  /** Minimum value (inclusive) */
  min: number;
}

MaxRuleOptions

ts
interface MaxRuleOptions {
  /** Maximum value (inclusive) */
  max: number;
}

RegexRuleOptions

ts
interface RegexRuleOptions {
  /** Pattern to match */
  pattern: RegExp;
  
  /** Invert match - fail if pattern matches (default: false) */
  invert?: boolean;
}

EqualsRuleOptions

ts
interface EqualsRuleOptions {
  /** Field to compare against (from ctx.data) */
  field?: string;
  
  /** Static value to compare against */
  value?: unknown;
}

Usage Examples

Typed Registry

ts
import type { Registry } from '@pliant/core';

interface FormData {
  password: string;
  confirmPassword: string;
}

const registry: Registry<FormData> = createRegistry<FormData>();

Custom Rule with Types

ts
import type { RuleDef, Context, ErrorDetail } from '@pliant/core';

interface FormData {
  otherField: string;
}

const myRule: RuleDef<FormData> = {
  validate(value: unknown, ctx: Context<FormData>): ErrorDetail | null {
    if (ctx.data?.otherField === value) {
      return { code: 'matchesOther', field: 'otherField' };
    }
    return null;
  }
};

Typed Message Resolver

ts
import type { MessageCatalog, MessageFunction } from '@pliant/core';

const rangeMessage: MessageFunction = (detail) => {
  const { min, max, value } = detail as { min: number; max: number; value: number };
  return `Value ${value} must be between ${min} and ${max}`;
};

const messages: MessageCatalog = {
  required: 'This field is required',
  range: rangeMessage
};

Generic Helper Function

ts
import type { Registry, Context, ErrorMap } from '@pliant/core';
import { evaluateRules } from '@pliant/core';

function validateField<TData>(
  registry: Registry<TData>,
  field: string,
  value: unknown,
  rules: string[],
  data?: TData
): ErrorMap | null {
  const ctx: Context<TData> = { field, data };
  return evaluateRules(registry, value, ctx, rules);
}

Augmenting Types

If you need to extend the types:

ts
declare module '@pliant/core' {
  interface Context<TData> {
    /** Custom property */
    locale?: string;
  }
}

See Also

Released under the MIT License.