Type validation decorators ensure values are of the correct JavaScript/TypeScript primitive types. These decorators provide runtime type checking that complements TypeScript's compile-time type system, making them essential for validating data from external sources like APIs, user input, or parsed files.
Validate that values match expected JavaScript primitive types.
/**
* Check that value is a string
* @param validationOptions - Validation configuration options
*/
@IsString(validationOptions?: ValidationOptions): PropertyDecorator;
/**
* Check that value is a number (including NaN and Infinity)
* @param options - Number validation options
* @param validationOptions - Validation configuration options
*/
@IsNumber(options?: IsNumberOptions, validationOptions?: ValidationOptions): PropertyDecorator;
/**
* Check that value is a boolean
* @param validationOptions - Validation configuration options
*/
@IsBoolean(validationOptions?: ValidationOptions): PropertyDecorator;
/**
* Check that value is a Date object
* @param validationOptions - Validation configuration options
*/
@IsDate(validationOptions?: ValidationOptions): PropertyDecorator;
/**
* Check that value is an array
* @param validationOptions - Validation configuration options
*/
@IsArray(validationOptions?: ValidationOptions): PropertyDecorator;
/**
* Check that value is an object (and not null)
* @param validationOptions - Validation configuration options
*/
@IsObject(validationOptions?: ValidationOptions): PropertyDecorator;Specialized validation for numeric types with additional constraints.
/**
* Check that value is an integer (whole number)
* @param validationOptions - Validation configuration options
*/
@IsInt(validationOptions?: ValidationOptions): PropertyDecorator;
/**
* Options for number validation
*/
interface IsNumberOptions {
/** Allow NaN (default: false) */
allowNaN?: boolean;
/** Allow Infinity (default: false) */
allowInfinity?: boolean;
/** Maximum number of decimal places */
maxDecimalPlaces?: number;
}Validate that values are members of specific enumerations.
/**
* Check that value is a member of the specified enum
* @param entity - Enum object to validate against
* @param validationOptions - Validation configuration options
*/
@IsEnum(entity: object, validationOptions?: ValidationOptions): PropertyDecorator;import { IsString, IsNumber, IsBoolean, IsDate, IsArray, IsObject } from "class-validator";
class DataModel {
@IsString()
name: string;
@IsNumber()
age: number;
@IsBoolean()
isActive: boolean;
@IsDate()
createdAt: Date;
@IsArray()
tags: string[];
@IsObject()
metadata: object;
}
// Usage
const data = new DataModel();
data.name = "John Doe";
data.age = 25;
data.isActive = true;
data.createdAt = new Date();
data.tags = ["user", "premium"];
data.metadata = { source: "api" };import { IsInt, IsNumber } from "class-validator";
class CounterModel {
@IsInt()
count: number; // Must be whole number
@IsNumber({ maxDecimalPlaces: 2 })
price: number; // Can have up to 2 decimal places
@IsNumber({ allowNaN: false, allowInfinity: false })
score: number; // Finite number only
}
const counter = new CounterModel();
counter.count = 42; // Valid
counter.price = 19.99; // Valid
counter.score = 85.5; // Valid
// These would fail validation:
// counter.count = 3.14; // Not an integer
// counter.price = 19.999; // Too many decimal places
// counter.score = NaN; // NaN not allowedimport { IsEnum } from "class-validator";
enum UserRole {
ADMIN = "admin",
USER = "user",
MODERATOR = "moderator"
}
enum Status {
ACTIVE = 1,
INACTIVE = 0,
PENDING = 2
}
class User {
@IsString()
name: string;
@IsEnum(UserRole)
role: UserRole;
@IsEnum(Status)
status: Status;
}
const user = new User();
user.name = "Alice";
user.role = UserRole.ADMIN; // Valid
user.status = Status.ACTIVE; // Valid
// These would fail validation:
// user.role = "invalid-role"; // Not in UserRole enum
// user.status = 99; // Not in Status enumimport { IsArray, ArrayNotEmpty, ValidateNested } from "class-validator";
class Category {
@IsString()
name: string;
}
class Product {
@IsString()
name: string;
@IsArray()
@ArrayNotEmpty()
tags: string[];
@IsArray()
@ValidateNested({ each: true })
@Type(() => Category)
categories: Category[];
}
const product = new Product();
product.name = "Laptop";
product.tags = ["electronics", "computers"]; // Valid array of strings
product.categories = [
{ name: "Electronics" },
{ name: "Computers" }
]; // Valid array of Category objectsimport { IsObject, ValidateNested, IsNotEmptyObject } from "class-validator";
class Address {
@IsString()
street: string;
@IsString()
city: string;
}
class User {
@IsString()
name: string;
@IsObject()
@IsNotEmptyObject()
preferences: object; // Any non-empty object
@IsObject()
@ValidateNested()
@Type(() => Address)
address: Address; // Specific object type with validation
}
const user = new User();
user.name = "Bob";
user.preferences = { theme: "dark", notifications: true }; // Valid object
user.address = { street: "123 Main St", city: "Anytown" }; // Valid Address objectimport { IsString, IsNumber, IsBoolean, IsDate, IsArray, IsOptional } from "class-validator";
class ApiResponse {
@IsString()
id: string;
@IsString()
name: string;
@IsNumber()
value: number;
@IsBoolean()
active: boolean;
@IsDate()
@Type(() => Date)
timestamp: Date;
@IsArray()
@IsString({ each: true })
tags: string[];
@IsOptional()
@IsObject()
metadata?: object;
}
// Function to validate API response
async function processApiData(rawData: any): Promise<ApiResponse> {
const response = Object.assign(new ApiResponse(), rawData);
const errors = await validate(response);
if (errors.length > 0) {
throw new Error(`Invalid API data: ${errors.map(e => e.toString()).join(', ')}`);
}
return response;
}import { IsString, IsNumber, IsBoolean, IsEnum, IsOptional } from "class-validator";
enum Gender {
MALE = "male",
FEMALE = "female",
OTHER = "other"
}
class UserRegistrationForm {
@IsString()
@Length(2, 50)
firstName: string;
@IsString()
@Length(2, 50)
lastName: string;
@IsNumber()
@Min(13)
@Max(120)
age: number;
@IsEnum(Gender)
gender: Gender;
@IsBoolean()
agreeToTerms: boolean;
@IsOptional()
@IsString()
@Length(0, 500)
bio?: string;
}
// Usage with form data
function validateFormData(formData: any): Promise<ValidationError[]> {
const form = Object.assign(new UserRegistrationForm(), {
firstName: formData.firstName,
lastName: formData.lastName,
age: parseInt(formData.age), // Convert string to number
gender: formData.gender,
agreeToTerms: formData.agreeToTerms === 'true', // Convert string to boolean
bio: formData.bio
});
return validate(form);
}import { IsArray, ValidateNested } from "class-validator";
class MixedContent {
@IsString()
type: string;
@IsString()
value: string;
}
class Document {
@IsArray()
@ValidateNested({ each: true })
@Type(() => MixedContent)
content: MixedContent[];
}import { ValidateIf, IsString, IsNumber } from "class-validator";
class FlexibleData {
@IsString()
dataType: 'string' | 'number';
@ValidateIf(o => o.dataType === 'string')
@IsString()
stringValue?: string;
@ValidateIf(o => o.dataType === 'number')
@IsNumber()
numberValue?: number;
}import { IsObject, ValidateNested, IsOptional, Type } from "class-validator";
class ContactInfo {
@IsString()
email: string;
@IsOptional()
@IsString()
phone?: string;
}
class UserProfile {
@IsString()
username: string;
@IsObject()
@ValidateNested()
@Type(() => ContactInfo)
contact: ContactInfo;
@IsOptional()
@IsObject()
@ValidateNested()
@Type(() => ContactInfo)
emergencyContact?: ContactInfo;
}