CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue-types

Prop type definitions for Vue.js components with runtime validation and TypeScript support

Pending
Overview
Eval results
Files

complex-validators.mddocs/

Complex Validators

Complex validators provide advanced validation patterns for custom types, enums, collections, and structured objects.

Capabilities

Custom Validator

Creates validators with user-defined validation functions for complex business logic.

/**
 * Creates a custom validator with user-defined validation function
 * @param validatorFn - Function that returns true if value is valid
 * @param warnMsg - Optional custom warning message on validation failure
 * @returns VueTypeDef with custom validation logic
 */
static custom<T>(
  validatorFn: ValidatorFunction<T>, 
  warnMsg?: string
): VueTypeDef<T>;

// Standalone function
function custom<T>(
  validatorFn: ValidatorFunction<T>,
  warnMsg?: string  
): VueTypeDef<T>;

// Validator function signature
type ValidatorFunction<T> = (
  value: T,
  props?: Record<string, unknown>
) => boolean;

Usage Examples:

import VueTypes, { custom } from "vue-types";

// Email validation
const email = custom<string>(
  (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
  'must be a valid email address'
);

// Range validation
const percentage = custom<number>(
  (value) => value >= 0 && value <= 100,
  'must be between 0 and 100'
);

// Complex object validation
const userProfile = custom<{ name: string; age: number }>(
  (value) => value.name.length > 0 && value.age >= 0,
  'invalid user profile'
);

// Usage in component
export default {
  props: {
    userEmail: email.isRequired,
    completion: percentage.def(0),
    profile: userProfile.isRequired
  }
};

One Of Validator

Validates that a value is one of a specific set of allowed values (enum-style validation).

/**
 * Creates a validator that accepts only specific values
 * @param arr - Array of allowed values
 * @returns VueTypeDef that accepts only values from the array
 */
static oneOf<T extends readonly any[]>(arr: T): VueTypeDef<T[number]>;  

// Standalone function
function oneOf<D, T extends readonly D[]>(arr: T): VueTypeDef<T[number]>;

Usage Examples:

import VueTypes, { oneOf } from "vue-types";

// String enum
const status = oneOf(['pending', 'success', 'error'] as const);
const theme = oneOf(['light', 'dark', 'auto'] as const);

// Mixed types
const priority = oneOf([1, 2, 3, 'high', 'low'] as const);

// With symbols
const eventType = oneOf([Symbol('click'), Symbol('hover')] as const);

// Usage in component
export default {
  props: {
    currentStatus: status.def('pending'),
    appTheme: theme.isRequired,
    taskPriority: priority.def(1)
  }
};

One Of Type Validator

Validates that a value matches one of multiple type definitions.

/**
 * Creates a validator that accepts values matching any of multiple types
 * @param arr - Array of type definitions to match against
 * @returns VueTypeDef that accepts values matching any provided type
 */
static oneOfType<T extends VueProp<any>[]>(
  arr: T
): VueTypeDef<InferType<T[number]>>;

// Standalone function  
function oneOfType<D extends V, U extends VueProp<any>, V = InferType<U>>(
  arr: U[]
): VueTypeDef<D>;

Usage Examples:

import VueTypes, { oneOfType, string, number, object } from "vue-types";

// String or number
const stringOrNumber = oneOfType([string(), number()]);

// Complex type union
const idValue = oneOfType([
  string(),
  number(),
  object<{ type: string; value: any }>()
]);

// With Vue native types
const mixedInput = oneOfType([
  String,
  Number,
  VueTypes.shape({ label: string(), value: string() })
]);

// Usage in component
export default {
  props: {
    id: stringOrNumber.isRequired,
    value: idValue.def(''),
    input: mixedInput.isRequired
  }
};

Array Of Validator

Validates arrays where all elements match a specific type definition.

/**
 * Creates a validator for arrays with typed elements
 * @param type - Type definition that all array elements must match
 * @returns VueTypeDef for arrays of the specified type
 */
static arrayOf<T extends VueProp<any>>(type: T): VueTypeDef<InferType<T>[]>;

// Standalone function
function arrayOf<T extends VueProp<any>>(type: T): VueTypeDef<InferType<T>[]>;

Usage Examples:

import VueTypes, { arrayOf, string, number, shape } from "vue-types";

// Array of strings
const tags = arrayOf(string());
const categories = arrayOf(VueTypes.string);

// Array of numbers
const scores = arrayOf(number()).def(() => []);

// Array of objects
const users = arrayOf(shape({
  name: string().isRequired,
  age: number(),
  email: string()
}));

// Nested arrays
const matrix = arrayOf(arrayOf(number()));

// Usage in component
export default {
  props: {
    postTags: tags.def(() => []),
    testScores: scores.isRequired,
    userList: users.def(() => []),
    numberMatrix: matrix.def(() => [])
  }
};

Object Of Validator

Validates objects where all property values match a specific type definition.

/**
 * Creates a validator for objects with typed property values
 * @param type - Type definition that all object values must match
 * @returns VueTypeDef for objects with values of the specified type
 */
static objectOf<T extends VueProp<any>>(
  type: T
): VueTypeDef<Record<string, InferType<T>>>;

// Standalone function
function objectOf<T extends VueProp<any>>(
  type: T  
): VueTypeDef<Record<string, InferType<T>>>;

Usage Examples:

import VueTypes, { objectOf, string, number, arrayOf } from "vue-types";

// Object with string values
const translations = objectOf(string());

// Object with number values  
const scores = objectOf(number()).def(() => ({}));

// Object with complex values
const userPreferences = objectOf(arrayOf(string()));

// Nested structure
const categoryItems = objectOf(objectOf(string()));

// Usage in component
export default {
  props: {
    i18n: translations.isRequired,
    gameScores: scores.def(() => ({})),
    preferences: userPreferences.def(() => ({})),
    catalog: categoryItems.def(() => ({}))
  }
};

Instance Of Validator

Validates that values are instances of a specific constructor function or class.

/**
 * Creates a validator for class instances
 * @param instanceConstructor - Constructor function to validate against
 * @returns VueTypeDef for instances of the specified constructor
 */
static instanceOf<C extends Constructor>(
  instanceConstructor: C
): VueTypeDef<InstanceType<C>>;

// Standalone function
function instanceOf<C extends Constructor>(
  instanceConstructor: C
): VueTypeDef<InstanceType<C>>;

// Constructor type
type Constructor = new (...args: any[]) => any;

Usage Examples:

import VueTypes, { instanceOf } from "vue-types";

// Built-in classes
const timestamp = instanceOf(Date);
const pattern = instanceOf(RegExp);
const errorInstance = instanceOf(Error);

// Custom classes
class User {
  constructor(public name: string, public id: number) {}
}

class ApiClient {
  constructor(private baseUrl: string) {}
}

const user = instanceOf(User);
const client = instanceOf(ApiClient);

// Usage in component
export default {
  props: {
    createdAt: timestamp.isRequired,
    validator: pattern.def(() => /.*/),
    currentUser: user.isRequired,
    apiClient: client.isRequired
  }
};

Shape Validator

Validates object structure with defined property types and supports loose validation.

/**
 * Creates a validator for objects with specific structure
 * @param obj - Object defining the required structure and property types
 * @returns VueTypeShape with strict validation and loose mode support
 */
static shape<T extends object>(obj: {
  [K in keyof T]: Prop<T[K]> | VueProp<T[K]>
}): VueTypeShape<T>;

// Standalone function
function shape<T extends object>(obj: {
  [K in keyof T]: Prop<T[K]> | VueProp<T[K]>
}): VueTypeShape<T>;

// Shape interfaces
interface VueTypeShape<T> extends VueTypeBaseDef<T> {
  readonly loose: VueTypeLooseShape<T>;
}

interface VueTypeLooseShape<T> extends VueTypeBaseDef<T> {
  readonly loose: VueTypeLooseShape<T>;
  readonly _vueTypes_isLoose: true;
}

Usage Examples:

import VueTypes, { shape, string, number, bool, arrayOf } from "vue-types";

// Basic object shape
const userShape = shape({
  name: string().isRequired,
  age: number(),
  email: string()
});

// Nested shapes
const addressShape = shape({
  street: string().isRequired,
  city: string().isRequired,
  zipCode: string(),
  country: string().def('US')
});

const userWithAddress = shape({
  name: string().isRequired,
  address: addressShape.isRequired,
  isActive: bool().def(true)
});

// Shape with arrays
const blogPost = shape({
  title: string().isRequired,
  content: string().isRequired,
  tags: arrayOf(string()).def(() => []),
  publishedAt: VueTypes.instanceOf(Date)
});

// Loose shape (allows additional properties)
const flexibleConfig = shape({
  theme: string().def('light'),
  debug: bool().def(false)
}).loose;

// Usage in component
export default {
  props: {
    user: userShape.isRequired,
    profile: userWithAddress.def(() => ({
      name: '',
      address: { street: '', city: '' },
      isActive: true
    })),
    post: blogPost.isRequired,
    settings: flexibleConfig.def(() => ({ theme: 'light', debug: false }))
  }
};

Advanced Patterns

Combining Validators

Complex validation scenarios can be achieved by combining different validators:

// Union of specific shapes
const notificationSettings = oneOfType([
  shape({
    type: oneOf(['email'] as const),
    address: string().isRequired
  }),
  shape({
    type: oneOf(['sms'] as const),
    phone: string().isRequired
  }),
  shape({
    type: oneOf(['push'] as const),
    deviceId: string().isRequired
  })
]);

// Conditional validation
const conditionalField = custom<any>((value, props) => {
  if (props?.requiresValidation) {
    return typeof value === 'string' && value.length > 0;
  }
  return true;
});

Error Handling

Complex validators provide detailed error messages for debugging:

// Custom error messages
const strongPassword = custom<string>(
  (value) => {
    return value.length >= 8 && 
           /[A-Z]/.test(value) && 
           /[a-z]/.test(value) && 
           /\d/.test(value);
  },
  'password must be at least 8 characters with uppercase, lowercase, and numbers'
);

// Shape validation shows specific property errors
const userProfile = shape({
  username: string().validate((value) => value.length >= 3),
  email: custom<string>((value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
});

TypeScript Integration

Complex validators maintain full type safety:

// Inferred types
const user = shape({
  name: string(),
  age: number(),
  isActive: bool()
});
// TypeScript infers: VueTypeShape<{ name: string; age: number; isActive: boolean }>

// Generic constraints
const apiResponse = shape({
  data: custom<User[]>((value) => Array.isArray(value)),
  status: oneOf(['success', 'error'] as const),
  message: string()
});

Install with Tessl CLI

npx tessl i tessl/npm-vue-types

docs

complex-validators.md

config-utilities.md

index.md

native-validators.md

type-system.md

tile.json