0
# Type Guards and Validation
1
2
Runtime validation functions for payload structure verification and type narrowing, including schema-specific type guards and comprehensive validation utilities for ensuring payload integrity.
3
4
## Capabilities
5
6
### Basic Payload Validation
7
8
Core functions for validating payload structure and type narrowing at runtime.
9
10
```typescript { .api }
11
/**
12
* Type guard to check if a value is any valid payload
13
* @param value - Value to check
14
* @returns True if value is a payload with schema property
15
*/
16
function isAnyPayload(value: unknown): value is Payload;
17
18
/**
19
* Type assertion factory for any payload
20
* @param value - Value to assert as payload
21
* @returns Value cast as Payload or throws error
22
*/
23
function asAnyPayload(value: unknown): Payload;
24
25
/**
26
* Higher-order function to create type guards for specific schemas
27
* @param schema - Array of schema strings to validate against
28
* @returns Type guard function for the specified schemas
29
*/
30
function isPayload<T extends Payload>(schema: string[]): (value: unknown) => value is T;
31
32
/**
33
* Higher-order function to create type assertion factories for specific schemas
34
* @param schema - Array of schema strings to validate against
35
* @returns Type assertion function for the specified schemas
36
*/
37
function asPayload<T extends Payload>(schema: string[]): (value: unknown) => T;
38
```
39
40
**Usage Examples:**
41
42
```typescript
43
import { isAnyPayload, asAnyPayload, isPayload } from "@xyo-network/payload-model";
44
45
// Check if value is any payload
46
const data: unknown = { schema: "network.example.test", message: "hello" };
47
48
if (isAnyPayload(data)) {
49
// TypeScript knows data is a Payload
50
console.log(data.schema);
51
}
52
53
// Create specific schema validators
54
const isUserPayload = isPayload<UserPayload>(["network.example.user"]);
55
const isProductPayload = isPayload<ProductPayload>(["network.example.product"]);
56
57
// Validate multiple schemas
58
const isValidPayload = isPayload([
59
"network.example.user",
60
"network.example.product",
61
"network.example.order"
62
]);
63
64
const unknownPayload: unknown = {
65
schema: "network.example.user",
66
name: "Alice",
67
email: "alice@example.com"
68
};
69
70
if (isUserPayload(unknownPayload)) {
71
// TypeScript knows this is UserPayload
72
console.log(unknownPayload.name);
73
}
74
75
// Type assertion
76
try {
77
const payload = asAnyPayload(data);
78
console.log("Valid payload:", payload.schema);
79
} catch (error) {
80
console.error("Invalid payload");
81
}
82
```
83
84
### Schema-Specific Type Guards
85
86
Advanced type guards for specific schema validation and type narrowing with enhanced type safety.
87
88
```typescript { .api }
89
/**
90
* Creates a type guard for a specific schema type
91
* @param schema - The schema string to validate against
92
* @returns Type guard function that narrows to the specific payload type
93
*/
94
function isPayloadOfSchemaType<T extends Payload | never = never>(
95
schema: T['schema']
96
): (x?: unknown | null) => x is T;
97
98
/**
99
* Creates a type guard for payloads with sources metadata
100
* @param schema - The schema string to validate against
101
* @returns Type guard function for payload with sources
102
*/
103
function isPayloadOfSchemaTypeWithSources<T extends Payload | never = never>(
104
schema: T['schema']
105
): (x?: unknown | null) => x is WithSources<T>;
106
107
/**
108
* Creates a negated type guard (returns true if NOT the specified schema)
109
* @param schema - The schema string to validate against
110
* @returns Type guard function that returns true if payload is NOT the specified schema
111
*/
112
function notPayloadOfSchemaType<T extends Payload | never = never>(
113
schema: T['schema']
114
): (x?: unknown | null) => x is T;
115
```
116
117
**Usage Examples:**
118
119
```typescript
120
import {
121
isPayloadOfSchemaType,
122
isPayloadOfSchemaTypeWithSources,
123
notPayloadOfSchemaType
124
} from "@xyo-network/payload-model";
125
126
// Define specific payload types
127
const UserSchema = "network.example.user" as const;
128
const ProductSchema = "network.example.product" as const;
129
130
interface UserPayload extends Payload {
131
schema: typeof UserSchema;
132
name: string;
133
email: string;
134
}
135
136
interface ProductPayload extends Payload {
137
schema: typeof ProductSchema;
138
name: string;
139
price: number;
140
}
141
142
// Create schema-specific type guards
143
const isUserPayload = isPayloadOfSchemaType<UserPayload>(UserSchema);
144
const isProductPayload = isPayloadOfSchemaType<ProductPayload>(ProductSchema);
145
const isUserWithSources = isPayloadOfSchemaTypeWithSources<UserPayload>(UserSchema);
146
147
// Usage in filtering
148
const payloads: Payload[] = [
149
{ schema: UserSchema, name: "Alice", email: "alice@example.com" },
150
{ schema: ProductSchema, name: "Laptop", price: 999 },
151
{ schema: UserSchema, name: "Bob", email: "bob@example.com" }
152
];
153
154
// Filter to specific payload types
155
const userPayloads = payloads.filter(isUserPayload);
156
const productPayloads = payloads.filter(isProductPayload);
157
158
// Type narrowing in conditionals
159
const unknownPayload: unknown = {
160
schema: UserSchema,
161
name: "Charlie",
162
email: "charlie@example.com"
163
};
164
165
if (isUserPayload(unknownPayload)) {
166
// TypeScript knows this is UserPayload
167
console.log(`User: ${unknownPayload.name} (${unknownPayload.email})`);
168
}
169
170
// Check for payloads with sources
171
const payloadWithSources: unknown = {
172
schema: UserSchema,
173
name: "David",
174
email: "david@example.com",
175
$sources: ["0x123..."]
176
};
177
178
if (isUserWithSources(payloadWithSources)) {
179
// TypeScript knows this has $sources array
180
console.log(`User with ${payloadWithSources.$sources.length} sources`);
181
}
182
183
// Negated validation
184
const nonUserPayloads = payloads.filter(notPayloadOfSchemaType(UserSchema));
185
```
186
187
### Schema Validation
188
189
Direct schema validation functions for string-based schema checking.
190
191
```typescript { .api }
192
/**
193
* Type guard to validate schema string format
194
* @param value - Value to check as schema
195
* @returns True if value matches schema regex pattern
196
*/
197
function isSchema(value: unknown): value is Schema;
198
199
/**
200
* Type assertion for schema strings
201
* @param value - Value to assert as schema
202
* @returns Value cast as Schema or throws error
203
*/
204
function asSchema(value: unknown): Schema;
205
```
206
207
**Usage Examples:**
208
209
```typescript
210
import { isSchema, asSchema } from "@xyo-network/payload-model";
211
212
// Validate schema format
213
const possibleSchema = "network.example.test";
214
215
if (isSchema(possibleSchema)) {
216
// TypeScript knows this is a valid Schema
217
console.log("Valid schema:", possibleSchema);
218
}
219
220
// Schema format validation
221
const schemas = [
222
"network.xyo.payload", // Valid
223
"network.example.user", // Valid
224
"invalid.schema.format.123", // May be invalid depending on regex
225
"network..empty.segment", // Invalid
226
"UPPERCASE.SCHEMA" // Invalid (must be lowercase)
227
];
228
229
const validSchemas = schemas.filter(isSchema);
230
console.log("Valid schemas:", validSchemas);
231
232
// Type assertion
233
try {
234
const schema = asSchema("network.example.valid");
235
console.log("Schema:", schema);
236
} catch (error) {
237
console.error("Invalid schema format");
238
}
239
240
// Dynamic schema validation
241
function createPayload(schemaStr: string, data: any) {
242
if (isSchema(schemaStr)) {
243
return {
244
schema: schemaStr,
245
...data
246
};
247
}
248
throw new Error("Invalid schema format");
249
}
250
```
251
252
### Validation Utilities
253
254
Additional validation utilities for working with payload collections and advanced validation scenarios.
255
256
```typescript { .api }
257
/**
258
* Type assertion factory that creates validation functions
259
*/
260
const AsObjectFactory: {
261
create<T>(guard: (value: unknown) => value is T): (value: unknown) => T;
262
createOptional<T>(guard: (value: unknown) => value is T): (value: unknown) => T | undefined;
263
};
264
```
265
266
**Usage Examples:**
267
268
```typescript
269
import { AsObjectFactory, isPayloadOfSchemaType } from "@xyo-network/payload-model";
270
271
// Create custom assertion functions
272
const UserSchema = "network.example.user" as const;
273
interface UserPayload extends Payload {
274
schema: typeof UserSchema;
275
name: string;
276
email: string;
277
}
278
279
const isUserPayload = isPayloadOfSchemaType<UserPayload>(UserSchema);
280
const asUserPayload = AsObjectFactory.create(isUserPayload);
281
const asOptionalUserPayload = AsObjectFactory.createOptional(isUserPayload);
282
283
// Use assertions
284
const data: unknown = {
285
schema: UserSchema,
286
name: "Alice",
287
email: "alice@example.com"
288
};
289
290
try {
291
const userPayload = asUserPayload(data);
292
console.log("User:", userPayload.name);
293
} catch (error) {
294
console.error("Not a valid user payload");
295
}
296
297
// Optional assertion (returns undefined instead of throwing)
298
const optionalUser = asOptionalUserPayload(data);
299
if (optionalUser) {
300
console.log("Optional user:", optionalUser.name);
301
}
302
303
// Process arrays with validation
304
const payloadData: unknown[] = [
305
{ schema: UserSchema, name: "Alice", email: "alice@example.com" },
306
{ schema: "network.example.product", name: "Laptop", price: 999 },
307
{ invalid: "data" }
308
];
309
310
const validUsers = payloadData
311
.map(asOptionalUserPayload)
312
.filter((user): user is UserPayload => user !== undefined);
313
314
console.log("Valid users:", validUsers.length);
315
```
316
317
## Advanced Usage Patterns
318
319
### Payload Type Discrimination
320
321
```typescript
322
import {
323
isPayloadOfSchemaType,
324
Payload
325
} from "@xyo-network/payload-model";
326
327
// Define multiple payload types
328
const UserSchema = "network.example.user" as const;
329
const ProductSchema = "network.example.product" as const;
330
const OrderSchema = "network.example.order" as const;
331
332
interface UserPayload extends Payload {
333
schema: typeof UserSchema;
334
name: string;
335
email: string;
336
}
337
338
interface ProductPayload extends Payload {
339
schema: typeof ProductSchema;
340
name: string;
341
price: number;
342
}
343
344
interface OrderPayload extends Payload {
345
schema: typeof OrderSchema;
346
userId: string;
347
productIds: string[];
348
total: number;
349
}
350
351
// Create discriminated union
352
type AppPayload = UserPayload | ProductPayload | OrderPayload;
353
354
// Create type guards
355
const isUserPayload = isPayloadOfSchemaType<UserPayload>(UserSchema);
356
const isProductPayload = isPayloadOfSchemaType<ProductPayload>(ProductSchema);
357
const isOrderPayload = isPayloadOfSchemaType<OrderPayload>(OrderSchema);
358
359
// Process different payload types
360
function processPayload(payload: AppPayload) {
361
if (isUserPayload(payload)) {
362
return `User: ${payload.name}`;
363
} else if (isProductPayload(payload)) {
364
return `Product: ${payload.name} - $${payload.price}`;
365
} else if (isOrderPayload(payload)) {
366
return `Order: ${payload.productIds.length} items - $${payload.total}`;
367
}
368
369
// TypeScript ensures exhaustive checking
370
const _exhaustiveCheck: never = payload;
371
return _exhaustiveCheck;
372
}
373
```
374
375
## Types Reference
376
377
### Type Guard Functions
378
379
- **`isAnyPayload(value)`**: Check if value is any payload
380
- **`isPayload<T>(schemas)`**: Create schema-specific type guard
381
- **`isPayloadOfSchemaType<T>(schema)`**: Create single schema type guard
382
- **`isPayloadOfSchemaTypeWithSources<T>(schema)`**: Type guard with sources validation
383
- **`notPayloadOfSchemaType<T>(schema)`**: Negated schema type guard
384
- **`isSchema(value)`**: Validate schema string format
385
386
### Assertion Functions
387
388
- **`asAnyPayload(value)`**: Assert value as any payload
389
- **`asPayload<T>(schemas)`**: Create schema-specific assertion
390
- **`asSchema(value)`**: Assert value as schema string
391
392
### Utility Functions
393
394
- **`AsObjectFactory.create<T>(guard)`**: Create assertion function from type guard
395
- **`AsObjectFactory.createOptional<T>(guard)`**: Create optional assertion function