or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdschema-types.mdutilities.mdvalidation.md

utilities.mddocs/

0

# Utilities

1

2

Utility functions and advanced features for schema manipulation, references, lazy evaluation, and customization including localization and custom method extension.

3

4

## Capabilities

5

6

### Schema Navigation

7

8

Functions for navigating and extracting nested schemas from complex object structures.

9

10

```typescript { .api }

11

/**

12

* Navigate to a nested schema at a specific path

13

* @param schema - Root schema to navigate from

14

* @param path - Dot-notation path to target schema

15

* @param value - Optional value for context-dependent schemas

16

* @param context - Optional validation context

17

* @returns Schema at the specified path

18

* @throws Error if path is not found

19

*/

20

function reach(

21

schema: Schema,

22

path: string,

23

value?: any,

24

context?: any

25

): Schema;

26

27

/**

28

* Get nested schema and context information at path

29

* @param schema - Root schema to navigate from

30

* @param path - Dot-notation path to target schema

31

* @param value - Optional value for context-dependent schemas

32

* @param context - Optional validation context

33

* @returns Object containing schema and context at path

34

*/

35

function getIn(

36

schema: Schema,

37

path: string,

38

value?: any,

39

context?: any

40

): {

41

schema: Schema;

42

parent: any;

43

parentPath: string;

44

};

45

```

46

47

**Usage Examples:**

48

49

```typescript

50

import { object, string, array, reach, getIn } from "yup";

51

52

const userSchema = object({

53

profile: object({

54

name: string().required(),

55

addresses: array(object({

56

street: string().required(),

57

city: string().required(),

58

})),

59

}),

60

});

61

62

// Navigate to nested schema

63

const nameSchema = reach(userSchema, "profile.name");

64

const addressSchema = reach(userSchema, "profile.addresses[0]");

65

const citySchema = reach(userSchema, "profile.addresses[0].city");

66

67

// Validate using reached schema

68

await nameSchema.validate("John Doe"); // "John Doe"

69

70

// Get schema with context

71

const result = getIn(userSchema, "profile.addresses[0].city");

72

console.log(result.schema); // StringSchema for city

73

console.log(result.parentPath); // "profile.addresses[0]"

74

```

75

76

### Schema Detection

77

78

Utility for identifying yup schema objects.

79

80

```typescript { .api }

81

/**

82

* Check if a value is a yup schema

83

* @param value - Value to test

84

* @returns Type predicate indicating if value is a Schema

85

*/

86

function isSchema(value: any): value is Schema;

87

```

88

89

**Usage Examples:**

90

91

```typescript

92

import { string, number, isSchema } from "yup";

93

94

const stringSchema = string();

95

const numberValue = 42;

96

const plainObject = { type: "string" };

97

98

console.log(isSchema(stringSchema)); // true

99

console.log(isSchema(numberValue)); // false

100

console.log(isSchema(plainObject)); // false

101

102

// Use in conditional logic

103

function processInput(input: any) {

104

if (isSchema(input)) {

105

return input.describe();

106

} else {

107

return { value: input };

108

}

109

}

110

```

111

112

### References

113

114

Create references to other fields in the same validation context for cross-field validation and dependencies.

115

116

```typescript { .api }

117

/**

118

* Create a reference to another field in the validation context

119

* @param path - Path to the referenced field

120

* @param options - Reference configuration options

121

* @returns Reference object pointing to the specified path

122

*/

123

function ref(path: string, options?: ReferenceOptions): Reference;

124

125

interface ReferenceOptions {

126

/** Transform the referenced value before using it */

127

map?: (value: any) => any;

128

}

129

130

/**

131

* Reference class for cross-field dependencies

132

*/

133

class Reference {

134

/** Path being referenced */

135

key: string;

136

/** Whether reference points to validation context ($) */

137

isContext: boolean;

138

/** Whether reference points to current value (.) */

139

isValue: boolean;

140

/** Whether reference points to sibling field */

141

isSibling: boolean;

142

/** Parsed path segments */

143

path: string[];

144

/** Function to extract property value */

145

getter: (data: any) => any;

146

/** Optional value transformation function */

147

map?: (value: any) => any;

148

149

/**

150

* Get the referenced value from provided data

151

* @param value - Current field value

152

* @param parent - Parent object containing fields

153

* @param context - Validation context

154

* @returns Referenced value

155

*/

156

getValue(value?: any, parent?: any, context?: any): any;

157

158

/**

159

* Cast the referenced value

160

* @param value - Value to cast

161

* @param options - Cast options

162

* @returns Cast value

163

*/

164

cast(value: any, options?: CastOptions): any;

165

166

/**

167

* Resolve the reference (returns self)

168

* @returns This reference instance

169

*/

170

resolve(): Reference;

171

172

/**

173

* Get a description of the reference

174

* @returns Reference description object

175

*/

176

describe(): { type: "ref"; key: string };

177

178

/**

179

* String representation of the reference

180

* @returns String representation

181

*/

182

toString(): string;

183

184

/**

185

* Check if a value is a Reference

186

* @param value - Value to test

187

* @returns Type predicate for Reference

188

*/

189

static isRef(value: any): value is Reference;

190

}

191

```

192

193

**Usage Examples:**

194

195

```typescript

196

import { object, string, number, ref } from "yup";

197

198

// Basic reference usage

199

const schema = object({

200

password: string().min(8).required(),

201

confirmPassword: string()

202

.oneOf([ref("password")], "Passwords must match")

203

.required(),

204

});

205

206

// Reference with transformation

207

const priceSchema = object({

208

price: number().positive().required(),

209

discountedPrice: number()

210

.max(ref("price", {

211

map: (price) => price * 0.9 // 10% max discount

212

}), "Discount cannot exceed 10%")

213

.positive(),

214

});

215

216

// Context references (access validation context)

217

const contextSchema = object({

218

userRole: string().required(),

219

adminAction: string().when("$isAdmin", {

220

is: true,

221

then: (schema) => schema.required(),

222

otherwise: (schema) => schema.strip(),

223

}),

224

});

225

226

await contextSchema.validate(

227

{ userRole: "user", adminAction: "delete" },

228

{ context: { isAdmin: false } }

229

);

230

231

// Complex reference paths

232

const nestedSchema = object({

233

users: array(object({

234

name: string().required(),

235

email: string().email().required(),

236

})),

237

primaryUser: object({

238

name: string().oneOf([ref("users[0].name")], "Must match first user"),

239

}),

240

});

241

```

242

243

### Lazy Schemas

244

245

Create schemas that are resolved dynamically based on the value being validated, enabling recursive and self-referencing schemas.

246

247

```typescript { .api }

248

/**

249

* Create a lazy schema that resolves based on the value

250

* @param builder - Function that returns schema based on value

251

* @returns LazySchema instance

252

*/

253

function lazy<T>(

254

builder: (value: any, options: ResolveOptions) => Schema<T>

255

): LazySchema<T>;

256

257

interface ResolveOptions {

258

/** Current validation context */

259

context?: any;

260

/** Parent object */

261

parent?: any;

262

/** Field path */

263

path?: string;

264

}

265

266

/**

267

* Lazy schema that resolves to different schemas based on value

268

*/

269

class LazySchema<T = any> {

270

/**

271

* Clone the lazy schema

272

* @param spec - Modifications to apply

273

* @returns New LazySchema instance

274

*/

275

clone(spec?: Partial<LazySchemaSpec>): LazySchema<T>;

276

277

/**

278

* Make the lazy schema optional

279

* @returns New optional LazySchema

280

*/

281

optional(): LazySchema<T | undefined>;

282

283

/**

284

* Resolve to concrete schema based on value

285

* @param options - Resolution context options

286

* @returns Resolved concrete schema

287

*/

288

resolve(options: ResolveOptions): Schema<T>;

289

290

/**

291

* Cast value using resolved schema

292

* @param value - Value to cast

293

* @param options - Cast options

294

* @returns Cast value

295

*/

296

cast(value: any, options?: CastOptions): T;

297

298

/**

299

* Validate value using resolved schema

300

* @param value - Value to validate

301

* @param options - Validation options

302

* @returns Promise resolving to validated value

303

*/

304

validate(value: any, options?: ValidateOptions): Promise<T>;

305

306

/**

307

* Synchronously validate value using resolved schema

308

* @param value - Value to validate

309

* @param options - Validation options

310

* @returns Validated value

311

*/

312

validateSync(value: any, options?: ValidateOptions): T;

313

314

/**

315

* Validate at specific path using resolved schema

316

* @param path - Field path

317

* @param value - Root value

318

* @param options - Validation options

319

* @returns Promise resolving to field value

320

*/

321

validateAt(path: string, value: any, options?: ValidateOptions): Promise<any>;

322

323

/**

324

* Synchronously validate at path using resolved schema

325

* @param path - Field path

326

* @param value - Root value

327

* @param options - Validation options

328

* @returns Field value

329

*/

330

validateSyncAt(path: string, value: any, options?: ValidateOptions): any;

331

332

/**

333

* Check validity using resolved schema

334

* @param value - Value to check

335

* @param options - Validation options

336

* @returns Promise resolving to validity status

337

*/

338

isValid(value: any, options?: ValidateOptions): Promise<boolean>;

339

340

/**

341

* Synchronously check validity using resolved schema

342

* @param value - Value to check

343

* @param options - Validation options

344

* @returns Validity status

345

*/

346

isValidSync(value: any, options?: ValidateOptions): boolean;

347

348

/**

349

* Describe the lazy schema or resolved schema

350

* @param options - Description options

351

* @returns Schema description

352

*/

353

describe(options?: DescribeOptions): SchemaDescription;

354

355

/**

356

* Set or get lazy schema metadata

357

* @param metadata - Metadata to set (optional)

358

* @returns Metadata or new schema with metadata

359

*/

360

meta(): Record<string, any> | undefined;

361

meta(metadata: Record<string, any>): LazySchema<T>;

362

}

363

```

364

365

**Usage Examples:**

366

367

```typescript

368

import { object, string, array, lazy } from "yup";

369

370

// Recursive schema for nested comments

371

const commentSchema = lazy(() =>

372

object({

373

id: string().required(),

374

message: string().required(),

375

author: string().required(),

376

replies: array(commentSchema), // Self-reference

377

})

378

);

379

380

// Polymorphic schema based on type field

381

const shapeSchema = lazy((value) => {

382

switch (value?.type) {

383

case "circle":

384

return object({

385

type: string().equals(["circle"]),

386

radius: number().positive().required(),

387

});

388

case "rectangle":

389

return object({

390

type: string().equals(["rectangle"]),

391

width: number().positive().required(),

392

height: number().positive().required(),

393

});

394

default:

395

return object({

396

type: string().required(),

397

});

398

}

399

});

400

401

// Dynamic schema based on user role

402

const userDataSchema = lazy((value, options) => {

403

const isAdmin = options.context?.userRole === "admin";

404

405

const baseSchema = object({

406

name: string().required(),

407

email: string().email().required(),

408

});

409

410

if (isAdmin) {

411

return baseSchema.shape({

412

adminNotes: string(),

413

permissions: array(string()),

414

});

415

}

416

417

return baseSchema;

418

});

419

420

// Usage with context

421

await userDataSchema.validate(

422

{ name: "John", email: "john@example.com" },

423

{ context: { userRole: "admin" } }

424

);

425

```

426

427

### Value Formatting

428

429

Format values for display in error messages and debugging.

430

431

```typescript { .api }

432

/**

433

* Format a value for display in error messages

434

* @param value - Value to format

435

* @returns Human-readable string representation

436

*/

437

function printValue(value: any): string;

438

```

439

440

**Usage Examples:**

441

442

```typescript

443

import { printValue } from "yup";

444

445

console.log(printValue("hello")); // '"hello"'

446

console.log(printValue(42)); // "42"

447

console.log(printValue(null)); // "null"

448

console.log(printValue(undefined)); // "undefined"

449

console.log(printValue([1, 2, 3])); // "[1, 2, 3]"

450

console.log(printValue({ name: "John" })); // '{"name": "John"}'

451

console.log(printValue(new Date("2023-01-01"))); // "2023-01-01T00:00:00.000Z"

452

453

// Used in custom error messages

454

const customSchema = string().test(

455

"custom-test",

456

function(value) {

457

return `Expected string, got ${printValue(value)}`;

458

},

459

(value) => typeof value === "string"

460

);

461

```

462

463

### Localization

464

465

Customize error messages for different languages and locales.

466

467

```typescript { .api }

468

/**

469

* Set custom error messages for validation failures

470

* @param localeObject - Object containing custom error messages

471

*/

472

function setLocale(localeObject: LocaleObject): void;

473

474

/**

475

* Default English error message locale

476

*/

477

const defaultLocale: LocaleObject;

478

479

interface LocaleObject {

480

mixed?: MixedLocale;

481

string?: StringLocale;

482

number?: NumberLocale;

483

date?: DateLocale;

484

boolean?: BooleanLocale;

485

object?: ObjectLocale;

486

array?: ArrayLocale;

487

}

488

489

interface MixedLocale {

490

default?: string;

491

required?: string;

492

oneOf?: string;

493

notOneOf?: string;

494

defined?: string;

495

notType?: string;

496

}

497

498

interface StringLocale extends MixedLocale {

499

length?: string;

500

min?: string;

501

max?: string;

502

matches?: string;

503

email?: string;

504

url?: string;

505

uuid?: string;

506

trim?: string;

507

lowercase?: string;

508

uppercase?: string;

509

}

510

511

interface NumberLocale extends MixedLocale {

512

min?: string;

513

max?: string;

514

lessThan?: string;

515

moreThan?: string;

516

positive?: string;

517

negative?: string;

518

integer?: string;

519

}

520

521

interface DateLocale extends MixedLocale {

522

min?: string;

523

max?: string;

524

}

525

526

interface BooleanLocale extends MixedLocale {

527

isValue?: string;

528

}

529

530

interface ObjectLocale extends MixedLocale {

531

noUnknown?: string;

532

}

533

534

interface ArrayLocale extends MixedLocale {

535

min?: string;

536

max?: string;

537

length?: string;

538

}

539

```

540

541

**Usage Examples:**

542

543

```typescript

544

import { setLocale, string, number } from "yup";

545

546

// Set Spanish error messages

547

setLocale({

548

mixed: {

549

required: "Este campo es obligatorio",

550

notType: "Debe ser de tipo ${type}",

551

},

552

string: {

553

min: "Debe tener al menos ${min} caracteres",

554

max: "Debe tener como máximo ${max} caracteres",

555

email: "Debe ser un email válido",

556

},

557

number: {

558

min: "Debe ser mayor o igual a ${min}",

559

max: "Debe ser menor o igual a ${max}",

560

positive: "Debe ser un número positivo",

561

},

562

});

563

564

// Schemas will now use Spanish messages

565

const userSchema = object({

566

nombre: string().min(2).required(),

567

edad: number().positive().required(),

568

email: string().email().required(),

569

});

570

571

// Custom locale for specific domain

572

setLocale({

573

string: {

574

min: "Password must be at least ${min} characters long",

575

matches: "Password must contain uppercase, lowercase, and numbers",

576

},

577

});

578

579

// Reset to default locale

580

setLocale(defaultLocale);

581

```

582

583

### Custom Methods

584

585

Extend schema types with custom validation methods and functionality.

586

587

```typescript { .api }

588

/**

589

* Add custom methods to schema types

590

* @param schemaType - Schema constructor to extend

591

* @param methodName - Name of the method to add

592

* @param method - Implementation function

593

*/

594

function addMethod<T extends Schema>(

595

schemaType: new (...args: any[]) => T,

596

methodName: string,

597

method: (this: T, ...args: any[]) => T

598

): void;

599

```

600

601

**Usage Examples:**

602

603

```typescript

604

import { addMethod, string, StringSchema } from "yup";

605

606

// Add custom method to StringSchema

607

addMethod(StringSchema, "strongPassword", function() {

608

return this.test(

609

"strong-password",

610

"Password must contain uppercase, lowercase, number, and special character",

611

(value) => {

612

if (!value) return false;

613

return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/.test(value);

614

}

615

);

616

});

617

618

// Extend TypeScript interface for type safety

619

declare module "yup" {

620

interface StringSchema {

621

strongPassword(): StringSchema;

622

}

623

}

624

625

// Use custom method

626

const passwordSchema = string().min(8).strongPassword().required();

627

628

// Add method with parameters

629

addMethod(StringSchema, "containsWord", function(word: string) {

630

return this.test(

631

"contains-word",

632

`Must contain the word "${word}"`,

633

(value) => value?.includes(word) ?? false

634

);

635

});

636

637

declare module "yup" {

638

interface StringSchema {

639

containsWord(word: string): StringSchema;

640

}

641

}

642

643

const titleSchema = string().containsWord("yup").required();

644

645

// Add method to NumberSchema

646

addMethod(NumberSchema, "currency", function() {

647

return this.test(

648

"currency",

649

"Must be a valid currency amount",

650

(value) => {

651

if (value == null) return true;

652

return Number.isFinite(value) && Math.round(value * 100) === value * 100;

653

}

654

).transform((value) => {

655

return value != null ? Math.round(value * 100) / 100 : value;

656

});

657

});

658

659

declare module "yup" {

660

interface NumberSchema {

661

currency(): NumberSchema;

662

}

663

}

664

665

const priceSchema = number().positive().currency().required();

666

```

667

668

### Advanced Utilities

669

670

Additional utility functions and configurations for specialized use cases.

671

672

```typescript { .api }

673

/**

674

* Create ValidationError instances programmatically

675

* @param errors - Error messages or ValidationError instances

676

* @param value - Value that failed validation

677

* @param field - Field path where error occurred

678

* @param type - Type of validation error

679

* @returns ValidationError instance

680

*/

681

function createError(

682

errors: string | string[] | ValidationError | ValidationError[],

683

value?: any,

684

field?: string,

685

type?: string

686

): ValidationError;

687

688

/**

689

* Global configuration options for yup behavior

690

*/

691

interface YupConfig {

692

/** Default strict mode setting */

693

strict?: boolean;

694

/** Default abort early setting */

695

abortEarly?: boolean;

696

/** Default strip unknown setting */

697

stripUnknown?: boolean;

698

}

699

700

/**

701

* Configure global yup defaults

702

* @param config - Global configuration options

703

*/

704

function configure(config: YupConfig): void;

705

```

706

707

**Usage Examples:**

708

709

```typescript

710

import { createError, configure, ValidationError } from "yup";

711

712

// Create custom validation errors

713

const customError = createError(

714

"Custom validation failed",

715

"invalid-value",

716

"field.path",

717

"custom"

718

);

719

720

// Multiple errors

721

const multipleErrors = createError([

722

"First error message",

723

"Second error message"

724

], null, "field");

725

726

// Global configuration

727

configure({

728

strict: false,

729

abortEarly: false,

730

stripUnknown: true,

731

});

732

733

// Custom error aggregation utility

734

function aggregateErrors(errors: ValidationError[]): Record<string, string[]> {

735

const result: Record<string, string[]> = {};

736

737

errors.forEach(error => {

738

error.inner.forEach(innerError => {

739

if (innerError.path) {

740

if (!result[innerError.path]) {

741

result[innerError.path] = [];

742

}

743

result[innerError.path].push(innerError.message);

744

}

745

});

746

});

747

748

return result;

749

}

750

```