0
# Error Handling
1
2
Comprehensive error reporting with path information, nested error details, and custom error types for validation failures.
3
4
## Capabilities
5
6
### VError Class
7
8
Custom error class for validation failures with path information.
9
10
```typescript { .api }
11
/**
12
* Error thrown by validation. Besides an informative message, it includes
13
* the path to the property which triggered the failure.
14
*/
15
class VError extends Error {
16
constructor(public path: string, message: string);
17
}
18
```
19
20
**Usage Examples:**
21
22
```typescript
23
import { createCheckers, VError } from "ts-interface-checker";
24
import userTypes from "./user-ti";
25
26
const { User } = createCheckers(userTypes);
27
28
try {
29
User.check({ name: "Alice" }); // Missing age property
30
} catch (error) {
31
if (error instanceof VError) {
32
console.log("Path:", error.path); // "value.age"
33
console.log("Message:", error.message); // "value.age is missing"
34
35
// Extract just the property path
36
const propertyPath = error.path.replace(/^value\.?/, "");
37
console.log("Property:", propertyPath); // "age"
38
}
39
}
40
41
// Custom path reporting
42
User.setReportedPath("userData");
43
try {
44
User.check({ name: "Bob" });
45
} catch (error) {
46
if (error instanceof VError) {
47
console.log("Path:", error.path); // "userData.age"
48
}
49
}
50
```
51
52
### IErrorDetail Interface
53
54
Detailed error information structure for comprehensive error reporting.
55
56
```typescript { .api }
57
/**
58
* Describes errors as returned by validate() and validateStrict() methods
59
*/
60
interface IErrorDetail {
61
path: string;
62
message: string;
63
nested?: IErrorDetail[];
64
}
65
```
66
67
**Usage Examples:**
68
69
```typescript
70
const { User } = createCheckers(userTypes);
71
72
const invalidData = {
73
name: 123, // Should be string
74
profile: {
75
email: "not-an-email", // Invalid email format
76
age: "thirty" // Should be number
77
}
78
};
79
80
const errors = User.validate(invalidData);
81
if (errors) {
82
function printErrors(errorList: IErrorDetail[], indent = 0) {
83
for (const error of errorList) {
84
const prefix = " ".repeat(indent);
85
console.log(`${prefix}${error.path}: ${error.message}`);
86
87
if (error.nested) {
88
printErrors(error.nested, indent + 1);
89
}
90
}
91
}
92
93
printErrors(errors);
94
// Output:
95
// value.name: is not a string
96
// value.profile.email: is not a valid email
97
// value.profile.age: is not a number
98
}
99
```
100
101
### Error Context System
102
103
Internal context system for collecting and reporting validation errors.
104
105
```typescript { .api }
106
/**
107
* Context interface used during validation to collect error messages
108
*/
109
interface IContext {
110
fail(relPath: string|number|null, message: string|null, score: number): false;
111
unionResolver(): IUnionResolver;
112
resolveUnion(ur: IUnionResolver): void;
113
fork(): IContext;
114
completeFork(): boolean;
115
failed(): boolean;
116
}
117
```
118
119
The context system is used internally but understanding it helps with advanced error handling:
120
121
**Context Types:**
122
123
```typescript { .api }
124
/**
125
* Union resolver interface for handling union type validation errors
126
*/
127
interface IUnionResolver {
128
createContext(): IContext;
129
}
130
131
/**
132
* Fast implementation for boolean-only validation (no error messages)
133
*/
134
class NoopContext implements IContext, IUnionResolver {
135
fail(relPath: string|number|null, message: string|null, score: number): false;
136
fork(): IContext;
137
completeFork(): boolean;
138
failed(): boolean;
139
unionResolver(): IUnionResolver;
140
createContext(): IContext;
141
resolveUnion(ur: IUnionResolver): void;
142
}
143
144
/**
145
* Complete implementation that collects detailed error information
146
*/
147
class DetailContext implements IContext {
148
static maxForks: number; // Maximum number of errors recorded at one level (default: 3)
149
150
fail(relPath: string|number|null, message: string|null, score: number): false;
151
fork(): IContext;
152
completeFork(): boolean;
153
failed(): boolean;
154
unionResolver(): IUnionResolver;
155
resolveUnion(ur: IUnionResolver): void;
156
157
getError(path: string): VError;
158
getErrorDetails(path: string): IErrorDetail[];
159
}
160
```
161
162
### Error Handling Patterns
163
164
Common patterns for handling validation errors in applications.
165
166
**Usage Examples:**
167
168
```typescript
169
import { createCheckers, VError, IErrorDetail } from "ts-interface-checker";
170
171
const { User } = createCheckers(userTypes);
172
173
// Basic error handling with try-catch
174
function validateUserData(data: unknown): User | null {
175
try {
176
User.check(data);
177
return data as User;
178
} catch (error) {
179
if (error instanceof VError) {
180
console.error(`Validation failed at ${error.path}: ${error.message}`);
181
}
182
return null;
183
}
184
}
185
186
// Detailed error handling with validate()
187
function validateWithDetails(data: unknown): {
188
isValid: boolean;
189
user?: User;
190
errors?: IErrorDetail[]
191
} {
192
const errors = User.validate(data);
193
194
if (errors) {
195
return { isValid: false, errors };
196
}
197
198
return { isValid: true, user: data as User };
199
}
200
201
// API response error formatting
202
function formatValidationErrors(errors: IErrorDetail[]): string[] {
203
function extractMessages(errorList: IErrorDetail[]): string[] {
204
const messages: string[] = [];
205
206
for (const error of errorList) {
207
messages.push(`${error.path}: ${error.message}`);
208
209
if (error.nested) {
210
messages.push(...extractMessages(error.nested));
211
}
212
}
213
214
return messages;
215
}
216
217
return extractMessages(errors);
218
}
219
220
// Express.js middleware example
221
function validateRequestBody(checkerName: string) {
222
return (req: any, res: any, next: any) => {
223
const checker = checkers[checkerName];
224
const errors = checker.validate(req.body);
225
226
if (errors) {
227
return res.status(400).json({
228
error: "Validation failed",
229
details: formatValidationErrors(errors)
230
});
231
}
232
233
next();
234
};
235
}
236
```
237
238
### Error Message Customization
239
240
Understanding error message structure for custom handling.
241
242
**Error Message Types:**
243
244
```typescript
245
// Different error scenarios produce different message patterns:
246
247
// Missing required property
248
// Path: "value.age", Message: "is missing"
249
250
// Wrong type
251
// Path: "value.name", Message: "is not a string"
252
253
// Extra property (strict mode)
254
// Path: "value.extra", Message: "is extraneous"
255
256
// Union type mismatch
257
// Path: "value", Message: "is none of string, number"
258
259
// Array index error
260
// Path: "value[2]", Message: "is not a number"
261
262
// Nested object error
263
// Path: "value.profile.email", Message: "is not a string"
264
```
265
266
**Usage Examples:**
267
268
```typescript
269
// Custom error message processing
270
function processError(error: VError): { field: string; type: string; message: string } {
271
const path = error.path;
272
const message = error.message;
273
274
// Extract field name from path
275
const field = path.replace(/^value\.?/, "") || "root";
276
277
// Determine error type from message
278
let type = "unknown";
279
if (message.includes("is missing")) {
280
type = "required";
281
} else if (message.includes("is not a")) {
282
type = "type";
283
} else if (message.includes("is extraneous")) {
284
type = "extra";
285
} else if (message.includes("is none of")) {
286
type = "union";
287
}
288
289
return { field, type, message };
290
}
291
292
// Usage
293
try {
294
User.check({ name: 123 });
295
} catch (error) {
296
if (error instanceof VError) {
297
const processed = processError(error);
298
console.log(processed);
299
// { field: "name", type: "type", message: "value.name is not a string" }
300
}
301
}
302
```