0
# Object and Array Validation
1
2
Advanced validation for objects and arrays including shape validation, property checking, element validation, and structural constraints.
3
4
## Capabilities
5
6
### Object Validation
7
8
Comprehensive object validation with shape matching, property validation, and instance checking.
9
10
```typescript { .api }
11
/** Object validation predicate */
12
interface ObjectPredicate extends BasePredicate<object> {
13
// Structure validation
14
readonly plain: ObjectPredicate;
15
readonly empty: ObjectPredicate;
16
readonly nonEmpty: ObjectPredicate;
17
18
// Property validation
19
hasKeys(...keys: string[]): ObjectPredicate;
20
hasAnyKeys(...keys: string[]): ObjectPredicate;
21
valuesOfType<T>(predicate: BasePredicate<T>): ObjectPredicate;
22
deepValuesOfType<T>(predicate: Predicate<T>): ObjectPredicate;
23
24
// Shape validation
25
partialShape<S>(shape: S): ObjectPredicate;
26
exactShape<S>(shape: S): ObjectPredicate;
27
deepEqual(expected: object): ObjectPredicate;
28
instanceOf(instance: Function): ObjectPredicate;
29
}
30
31
/** Shape definition for object validation */
32
type Shape = {
33
[key: string]: BasePredicate<any> | Shape;
34
};
35
```
36
37
**Structure Validation Examples:**
38
39
```typescript
40
import ow from 'ow';
41
42
// Structure validation
43
ow({}, ow.object.plain); // Plain object, not class instance
44
ow({}, ow.object.empty); // Empty object
45
ow({ name: 'Alice' }, ow.object.nonEmpty); // Non-empty object
46
47
// Class instance vs plain object
48
class User { constructor(public name: string) {} }
49
ow(new User('Alice'), ow.object.instanceOf(User));
50
ow({ name: 'Alice' }, ow.object.plain);
51
```
52
53
**Property Validation Examples:**
54
55
```typescript
56
import ow from 'ow';
57
58
const user = { name: 'Alice', age: 30, address: { city: 'NYC' } };
59
60
// Property existence (supports dot-notation)
61
ow(user, ow.object.hasKeys('name', 'age'));
62
ow(user, ow.object.hasKeys('address.city'));
63
ow(user, ow.object.hasAnyKeys('name', 'email'));
64
65
// Value type validation
66
ow({ a: 1, b: 2, c: 3 }, ow.object.valuesOfType(ow.number));
67
ow(
68
{ nums: [1, 2], strs: ['a', 'b'] },
69
ow.object.deepValuesOfType(ow.any(ow.array, ow.string, ow.number))
70
);
71
```
72
73
**Shape Validation Examples:**
74
75
```typescript
76
import ow from 'ow';
77
78
// Partial shape - ignores extra properties
79
const userShape = {
80
name: ow.string,
81
age: ow.number.integer.positive
82
};
83
84
ow({ name: 'Alice', age: 30, extra: 'ignored' }, ow.object.partialShape(userShape));
85
86
// Exact shape - fails on extra properties
87
ow({ name: 'Alice', age: 30 }, ow.object.exactShape(userShape));
88
89
// Nested shape validation
90
const nestedShape = {
91
user: {
92
name: ow.string,
93
contacts: {
94
email: ow.optional.string,
95
phone: ow.optional.string
96
}
97
}
98
};
99
100
ow({
101
user: {
102
name: 'Alice',
103
contacts: {
104
email: 'alice@example.com'
105
}
106
}
107
}, ow.object.exactShape(nestedShape));
108
109
// Deep equality
110
ow({ a: 1, b: [2, 3] }, ow.object.deepEqual({ a: 1, b: [2, 3] }));
111
```
112
113
### Array Validation
114
115
Comprehensive array validation with length constraints, element validation, and content checking.
116
117
```typescript { .api }
118
/** Array validation predicate */
119
interface ArrayPredicate extends BasePredicate<unknown[]> {
120
// Length validation
121
length(length: number): ArrayPredicate;
122
minLength(length: number): ArrayPredicate;
123
maxLength(length: number): ArrayPredicate;
124
125
// Content validation
126
startsWith<T>(searchElement: T): ArrayPredicate;
127
endsWith<T>(searchElement: T): ArrayPredicate;
128
includes<T>(...searchElements: T[]): ArrayPredicate;
129
includesAny<T>(...searchElements: T[]): ArrayPredicate;
130
deepEqual<T>(expected: T[]): ArrayPredicate;
131
132
// State validation
133
readonly empty: ArrayPredicate;
134
readonly nonEmpty: ArrayPredicate;
135
136
// Type validation
137
ofType<U>(predicate: BasePredicate<U>): ArrayPredicate;
138
exactShape(predicates: BasePredicate[]): ArrayPredicate;
139
}
140
```
141
142
**Length Validation Examples:**
143
144
```typescript
145
import ow from 'ow';
146
147
// Length constraints
148
ow([1, 2, 3], ow.array.length(3));
149
ow([1, 2], ow.array.minLength(2));
150
ow([1, 2, 3], ow.array.maxLength(5));
151
ow([], ow.array.empty);
152
ow([1], ow.array.nonEmpty);
153
```
154
155
**Content Validation Examples:**
156
157
```typescript
158
import ow from 'ow';
159
160
const numbers = [1, 2, 3, 4, 5];
161
162
// Element position validation
163
ow(numbers, ow.array.startsWith(1));
164
ow(numbers, ow.array.endsWith(5));
165
166
// Content inclusion
167
ow(numbers, ow.array.includes(2, 3, 4));
168
ow(numbers, ow.array.includesAny(2, 10, 20));
169
170
// Deep equality
171
ow([[1, 2], [3, 4]], ow.array.deepEqual([[1, 2], [3, 4]]));
172
```
173
174
**Type Validation Examples:**
175
176
```typescript
177
import ow from 'ow';
178
179
// All elements must match predicate
180
ow([1, 2, 3], ow.array.ofType(ow.number.positive));
181
ow(['a', 'b', 'c'], ow.array.ofType(ow.string.nonEmpty));
182
183
// Mixed type arrays
184
ow([1, 'hello', true], ow.array.ofType(ow.any(ow.number, ow.string, ow.boolean)));
185
186
// Exact shape validation - elements match predicates at same indices
187
ow(['Alice', 30, true], ow.array.exactShape([
188
ow.string,
189
ow.number.integer.positive,
190
ow.boolean
191
]));
192
193
// Array of objects
194
const users = [
195
{ name: 'Alice', age: 30 },
196
{ name: 'Bob', age: 25 }
197
];
198
199
ow(users, ow.array.ofType(ow.object.exactShape({
200
name: ow.string,
201
age: ow.number.integer.positive
202
})));
203
```
204
205
## Advanced Usage Examples
206
207
### Nested Object and Array Validation
208
209
```typescript
210
import ow from 'ow';
211
212
// Complex nested structure
213
const apiResponse = {
214
users: [
215
{
216
id: 1,
217
profile: {
218
name: 'Alice',
219
contacts: ['alice@example.com', '+1-555-0123']
220
},
221
permissions: ['read', 'write']
222
}
223
],
224
meta: {
225
total: 1,
226
page: 1
227
}
228
};
229
230
const responseShape = {
231
users: ow.array.ofType(ow.object.exactShape({
232
id: ow.number.integer.positive,
233
profile: ow.object.exactShape({
234
name: ow.string.nonEmpty,
235
contacts: ow.array.ofType(ow.string.nonEmpty)
236
}),
237
permissions: ow.array.ofType(ow.string.oneOf(['read', 'write', 'admin']))
238
})),
239
meta: ow.object.exactShape({
240
total: ow.number.integer.positive,
241
page: ow.number.integer.positive
242
})
243
};
244
245
ow(apiResponse, ow.object.exactShape(responseShape));
246
```
247
248
### Dynamic Object Validation
249
250
```typescript
251
import ow from 'ow';
252
253
// Validate object with dynamic keys
254
const dynamicObject = {
255
'user:1': { name: 'Alice', active: true },
256
'user:2': { name: 'Bob', active: false }
257
};
258
259
// All keys must match pattern, all values must match shape
260
ow(Object.keys(dynamicObject), ow.array.ofType(ow.string.matches(/^user:\d+$/)));
261
ow(dynamicObject, ow.object.valuesOfType(ow.object.exactShape({
262
name: ow.string,
263
active: ow.boolean
264
})));
265
```
266
267
### Array Transformation Validation
268
269
```typescript
270
import ow from 'ow';
271
272
// Validate transformed arrays
273
const input = ['1', '2', '3'];
274
const numbers = input.map(Number);
275
276
ow(input, ow.array.ofType(ow.string.numeric));
277
ow(numbers, ow.array.ofType(ow.number.integer));
278
```