Skip to content

brunotot/typescript-decorator-validation

Repository files navigation

πŸš€ TypeScript Decorator Validation πŸš€

Downloads per month NPM Version Contributors Awesome badge

Maintained Tests TypeDocs

πŸ”Ž Frequently Asked Questions (FAQ)


🌟 Welcome to tdv-monorepo, the future of model validation in TypeScript.

Leveraging TypeScript decorators, tdv-monorepo offers a declarative way to manage model validation. Suitable for both client-side and server-side projects, it comes with built-in extensibility and localization support.

Features

  • powered by TypeScript's stage-3 decorators (type-safety included)
  • small in bundle size with no dependencies
  • built-in i18n localization support to supply the messages in the user's native language
  • well-documented code and extensive guides for making it easy to get started
  • designed to play nice with popular testing frameworks like Jest
  • integrates seamlessly within any native TypeScript v5+ project
  • provides a clean and declarative way of validating form fields
  • exports Reflection namespace containing useful reflection-related methods

Content

Installation

npm install -d typescript@latest
npm install tdv-core
npm install tdv-react # when using in framework-specific environment

Quick start

import {
  validate,
  collection,
  ValidationEngine,
  Localization,
  TdvCore,
} from "tdv-core";

function MinSize(min: number, groups: TdvCore.Validation.Groups = []) {
  return validate<string>({
    groups,
    isValid: (value: string, _parent: Foo, _locale: Localization.Locale) => ({
      key: "MinSize",
      valid: value.length >= min,
      message: `Input must contain at least ${min} characters`,
    }),
  });
}

class Foo {
  @collection.string.Email() // predefined
  @MinSize(10) // custom
  email!: string;
}

const engine = new ValidationEngine(Foo);
const result = engine.validate({ email: "invalid" });
console.log(result.errors.email);
// [ 'Input must contain at least 10 characters', 'Value is not a valid email' ]

Supported Frameworks

Documentation

Contribution

To contribute, simply clone the main branch, commit changes to a local branch and open pull request.
Branch will be ready for merge after all CI tests pass and a review has been made.

Future goals

  • Implement strict type checking
  • Implement predefined decorator validators
  • Provide source code documentation
  • Implement concise tests for various scenarios
  • Build implementation packages for popular front-end frameworks

Examples

A basic TypeScript form can look something like

import { decorate, ValidationEngine } from "tdv-core";

/**
 *  This is an optional layer of abstraction if the class contains complex
 *  validation evaluations which shouldn't be registered as properties.
 *  In this example the "passwordsMatch" field isn't a settable property.
 */
export type UserFormFields = {
  confirmPassword: string;
  firstName: string;
  lastName: string;
  password: string;
  url: string;
  age: number;
};

export default class UserForm implements UserFormFields {
  @collection.string.MinLength(5)
  @collection.string.Required()
  firstName!: string;

  @collection.string.Required()
  lastName!: string;

  @collection.string.Required()
  @collection.string.Password()
  password!: string;

  confirmPassword!: string;

  @collection.string.URL()
  url!: string;

  @collection.number.ValueRange({ min: 18, max: 100 })
  age!: number;

  @collection.boolean.Truthy("Passwords must match")
  get passwordsMatch(): boolean {
    return this.password === this.confirmPassword;
  }
}

And a sample value of type UserForm may look something like

const dummy: Partial<UserFormFields> = {
  firstName: "",
  lastName: "",
  password: "12345",
  confirmPassword: "",
  url: "",
  age: 10,
};

Now we can inspect the errors of the given sample value

const engine = new ValidationEngine(UserForm);
const { errors } = engine.validate(dummy);
console.log(errors);

And the result is

{
  firstName: [
    "Field is mandatory",
    "Field must contain at least 5 characters"
  ],
  lastName: [
    "Field is mandatory"
  ],
  password: [
    "Password must be at least 8 characters long"
  ],
  url: [
    // EMPTY
  ],
  age: [
    "Value must be greater than or equal to 18 and less than or equal to 100 but is 10"
  ],
  passwordsMatch: [
    "Passwords must match"
  ]
}

Repository architecture

The tdv-core package is the backbone, providing core validation logic that's framework-agnostic. Features include:

  • A decorator factory for easy integration with TypeScript
  • Metadata management for dynamic behavior
  • Localization support
  • Built-in validators like Email, Required, etc.

The core package serves as the foundation for implementation libraries like tdv-react, with future extensions planned for Angular, Vue, and Svelte. This modular design ensures that the core logic remains framework-agnostic, allowing for easy adaptability.