0
# Complex Validators
1
2
Complex validators provide advanced validation patterns for custom types, enums, collections, and structured objects.
3
4
## Capabilities
5
6
### Custom Validator
7
8
Creates validators with user-defined validation functions for complex business logic.
9
10
```typescript { .api }
11
/**
12
* Creates a custom validator with user-defined validation function
13
* @param validatorFn - Function that returns true if value is valid
14
* @param warnMsg - Optional custom warning message on validation failure
15
* @returns VueTypeDef with custom validation logic
16
*/
17
static custom<T>(
18
validatorFn: ValidatorFunction<T>,
19
warnMsg?: string
20
): VueTypeDef<T>;
21
22
// Standalone function
23
function custom<T>(
24
validatorFn: ValidatorFunction<T>,
25
warnMsg?: string
26
): VueTypeDef<T>;
27
28
// Validator function signature
29
type ValidatorFunction<T> = (
30
value: T,
31
props?: Record<string, unknown>
32
) => boolean;
33
```
34
35
**Usage Examples:**
36
37
```typescript
38
import VueTypes, { custom } from "vue-types";
39
40
// Email validation
41
const email = custom<string>(
42
(value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
43
'must be a valid email address'
44
);
45
46
// Range validation
47
const percentage = custom<number>(
48
(value) => value >= 0 && value <= 100,
49
'must be between 0 and 100'
50
);
51
52
// Complex object validation
53
const userProfile = custom<{ name: string; age: number }>(
54
(value) => value.name.length > 0 && value.age >= 0,
55
'invalid user profile'
56
);
57
58
// Usage in component
59
export default {
60
props: {
61
userEmail: email.isRequired,
62
completion: percentage.def(0),
63
profile: userProfile.isRequired
64
}
65
};
66
```
67
68
### One Of Validator
69
70
Validates that a value is one of a specific set of allowed values (enum-style validation).
71
72
```typescript { .api }
73
/**
74
* Creates a validator that accepts only specific values
75
* @param arr - Array of allowed values
76
* @returns VueTypeDef that accepts only values from the array
77
*/
78
static oneOf<T extends readonly any[]>(arr: T): VueTypeDef<T[number]>;
79
80
// Standalone function
81
function oneOf<D, T extends readonly D[]>(arr: T): VueTypeDef<T[number]>;
82
```
83
84
**Usage Examples:**
85
86
```typescript
87
import VueTypes, { oneOf } from "vue-types";
88
89
// String enum
90
const status = oneOf(['pending', 'success', 'error'] as const);
91
const theme = oneOf(['light', 'dark', 'auto'] as const);
92
93
// Mixed types
94
const priority = oneOf([1, 2, 3, 'high', 'low'] as const);
95
96
// With symbols
97
const eventType = oneOf([Symbol('click'), Symbol('hover')] as const);
98
99
// Usage in component
100
export default {
101
props: {
102
currentStatus: status.def('pending'),
103
appTheme: theme.isRequired,
104
taskPriority: priority.def(1)
105
}
106
};
107
```
108
109
### One Of Type Validator
110
111
Validates that a value matches one of multiple type definitions.
112
113
```typescript { .api }
114
/**
115
* Creates a validator that accepts values matching any of multiple types
116
* @param arr - Array of type definitions to match against
117
* @returns VueTypeDef that accepts values matching any provided type
118
*/
119
static oneOfType<T extends VueProp<any>[]>(
120
arr: T
121
): VueTypeDef<InferType<T[number]>>;
122
123
// Standalone function
124
function oneOfType<D extends V, U extends VueProp<any>, V = InferType<U>>(
125
arr: U[]
126
): VueTypeDef<D>;
127
```
128
129
**Usage Examples:**
130
131
```typescript
132
import VueTypes, { oneOfType, string, number, object } from "vue-types";
133
134
// String or number
135
const stringOrNumber = oneOfType([string(), number()]);
136
137
// Complex type union
138
const idValue = oneOfType([
139
string(),
140
number(),
141
object<{ type: string; value: any }>()
142
]);
143
144
// With Vue native types
145
const mixedInput = oneOfType([
146
String,
147
Number,
148
VueTypes.shape({ label: string(), value: string() })
149
]);
150
151
// Usage in component
152
export default {
153
props: {
154
id: stringOrNumber.isRequired,
155
value: idValue.def(''),
156
input: mixedInput.isRequired
157
}
158
};
159
```
160
161
### Array Of Validator
162
163
Validates arrays where all elements match a specific type definition.
164
165
```typescript { .api }
166
/**
167
* Creates a validator for arrays with typed elements
168
* @param type - Type definition that all array elements must match
169
* @returns VueTypeDef for arrays of the specified type
170
*/
171
static arrayOf<T extends VueProp<any>>(type: T): VueTypeDef<InferType<T>[]>;
172
173
// Standalone function
174
function arrayOf<T extends VueProp<any>>(type: T): VueTypeDef<InferType<T>[]>;
175
```
176
177
**Usage Examples:**
178
179
```typescript
180
import VueTypes, { arrayOf, string, number, shape } from "vue-types";
181
182
// Array of strings
183
const tags = arrayOf(string());
184
const categories = arrayOf(VueTypes.string);
185
186
// Array of numbers
187
const scores = arrayOf(number()).def(() => []);
188
189
// Array of objects
190
const users = arrayOf(shape({
191
name: string().isRequired,
192
age: number(),
193
email: string()
194
}));
195
196
// Nested arrays
197
const matrix = arrayOf(arrayOf(number()));
198
199
// Usage in component
200
export default {
201
props: {
202
postTags: tags.def(() => []),
203
testScores: scores.isRequired,
204
userList: users.def(() => []),
205
numberMatrix: matrix.def(() => [])
206
}
207
};
208
```
209
210
### Object Of Validator
211
212
Validates objects where all property values match a specific type definition.
213
214
```typescript { .api }
215
/**
216
* Creates a validator for objects with typed property values
217
* @param type - Type definition that all object values must match
218
* @returns VueTypeDef for objects with values of the specified type
219
*/
220
static objectOf<T extends VueProp<any>>(
221
type: T
222
): VueTypeDef<Record<string, InferType<T>>>;
223
224
// Standalone function
225
function objectOf<T extends VueProp<any>>(
226
type: T
227
): VueTypeDef<Record<string, InferType<T>>>;
228
```
229
230
**Usage Examples:**
231
232
```typescript
233
import VueTypes, { objectOf, string, number, arrayOf } from "vue-types";
234
235
// Object with string values
236
const translations = objectOf(string());
237
238
// Object with number values
239
const scores = objectOf(number()).def(() => ({}));
240
241
// Object with complex values
242
const userPreferences = objectOf(arrayOf(string()));
243
244
// Nested structure
245
const categoryItems = objectOf(objectOf(string()));
246
247
// Usage in component
248
export default {
249
props: {
250
i18n: translations.isRequired,
251
gameScores: scores.def(() => ({})),
252
preferences: userPreferences.def(() => ({})),
253
catalog: categoryItems.def(() => ({}))
254
}
255
};
256
```
257
258
### Instance Of Validator
259
260
Validates that values are instances of a specific constructor function or class.
261
262
```typescript { .api }
263
/**
264
* Creates a validator for class instances
265
* @param instanceConstructor - Constructor function to validate against
266
* @returns VueTypeDef for instances of the specified constructor
267
*/
268
static instanceOf<C extends Constructor>(
269
instanceConstructor: C
270
): VueTypeDef<InstanceType<C>>;
271
272
// Standalone function
273
function instanceOf<C extends Constructor>(
274
instanceConstructor: C
275
): VueTypeDef<InstanceType<C>>;
276
277
// Constructor type
278
type Constructor = new (...args: any[]) => any;
279
```
280
281
**Usage Examples:**
282
283
```typescript
284
import VueTypes, { instanceOf } from "vue-types";
285
286
// Built-in classes
287
const timestamp = instanceOf(Date);
288
const pattern = instanceOf(RegExp);
289
const errorInstance = instanceOf(Error);
290
291
// Custom classes
292
class User {
293
constructor(public name: string, public id: number) {}
294
}
295
296
class ApiClient {
297
constructor(private baseUrl: string) {}
298
}
299
300
const user = instanceOf(User);
301
const client = instanceOf(ApiClient);
302
303
// Usage in component
304
export default {
305
props: {
306
createdAt: timestamp.isRequired,
307
validator: pattern.def(() => /.*/),
308
currentUser: user.isRequired,
309
apiClient: client.isRequired
310
}
311
};
312
```
313
314
### Shape Validator
315
316
Validates object structure with defined property types and supports loose validation.
317
318
```typescript { .api }
319
/**
320
* Creates a validator for objects with specific structure
321
* @param obj - Object defining the required structure and property types
322
* @returns VueTypeShape with strict validation and loose mode support
323
*/
324
static shape<T extends object>(obj: {
325
[K in keyof T]: Prop<T[K]> | VueProp<T[K]>
326
}): VueTypeShape<T>;
327
328
// Standalone function
329
function shape<T extends object>(obj: {
330
[K in keyof T]: Prop<T[K]> | VueProp<T[K]>
331
}): VueTypeShape<T>;
332
333
// Shape interfaces
334
interface VueTypeShape<T> extends VueTypeBaseDef<T> {
335
readonly loose: VueTypeLooseShape<T>;
336
}
337
338
interface VueTypeLooseShape<T> extends VueTypeBaseDef<T> {
339
readonly loose: VueTypeLooseShape<T>;
340
readonly _vueTypes_isLoose: true;
341
}
342
```
343
344
**Usage Examples:**
345
346
```typescript
347
import VueTypes, { shape, string, number, bool, arrayOf } from "vue-types";
348
349
// Basic object shape
350
const userShape = shape({
351
name: string().isRequired,
352
age: number(),
353
email: string()
354
});
355
356
// Nested shapes
357
const addressShape = shape({
358
street: string().isRequired,
359
city: string().isRequired,
360
zipCode: string(),
361
country: string().def('US')
362
});
363
364
const userWithAddress = shape({
365
name: string().isRequired,
366
address: addressShape.isRequired,
367
isActive: bool().def(true)
368
});
369
370
// Shape with arrays
371
const blogPost = shape({
372
title: string().isRequired,
373
content: string().isRequired,
374
tags: arrayOf(string()).def(() => []),
375
publishedAt: VueTypes.instanceOf(Date)
376
});
377
378
// Loose shape (allows additional properties)
379
const flexibleConfig = shape({
380
theme: string().def('light'),
381
debug: bool().def(false)
382
}).loose;
383
384
// Usage in component
385
export default {
386
props: {
387
user: userShape.isRequired,
388
profile: userWithAddress.def(() => ({
389
name: '',
390
address: { street: '', city: '' },
391
isActive: true
392
})),
393
post: blogPost.isRequired,
394
settings: flexibleConfig.def(() => ({ theme: 'light', debug: false }))
395
}
396
};
397
```
398
399
## Advanced Patterns
400
401
### Combining Validators
402
403
Complex validation scenarios can be achieved by combining different validators:
404
405
```typescript
406
// Union of specific shapes
407
const notificationSettings = oneOfType([
408
shape({
409
type: oneOf(['email'] as const),
410
address: string().isRequired
411
}),
412
shape({
413
type: oneOf(['sms'] as const),
414
phone: string().isRequired
415
}),
416
shape({
417
type: oneOf(['push'] as const),
418
deviceId: string().isRequired
419
})
420
]);
421
422
// Conditional validation
423
const conditionalField = custom<any>((value, props) => {
424
if (props?.requiresValidation) {
425
return typeof value === 'string' && value.length > 0;
426
}
427
return true;
428
});
429
```
430
431
### Error Handling
432
433
Complex validators provide detailed error messages for debugging:
434
435
```typescript
436
// Custom error messages
437
const strongPassword = custom<string>(
438
(value) => {
439
return value.length >= 8 &&
440
/[A-Z]/.test(value) &&
441
/[a-z]/.test(value) &&
442
/\d/.test(value);
443
},
444
'password must be at least 8 characters with uppercase, lowercase, and numbers'
445
);
446
447
// Shape validation shows specific property errors
448
const userProfile = shape({
449
username: string().validate((value) => value.length >= 3),
450
email: custom<string>((value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
451
});
452
```
453
454
### TypeScript Integration
455
456
Complex validators maintain full type safety:
457
458
```typescript
459
// Inferred types
460
const user = shape({
461
name: string(),
462
age: number(),
463
isActive: bool()
464
});
465
// TypeScript infers: VueTypeShape<{ name: string; age: number; isActive: boolean }>
466
467
// Generic constraints
468
const apiResponse = shape({
469
data: custom<User[]>((value) => Array.isArray(value)),
470
status: oneOf(['success', 'error'] as const),
471
message: string()
472
});
473
```