or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

checker-creation.mddata-validation.mderror-handling.mdindex.mdinterface-method-validation.mdtype-definition-system.md

error-handling.mddocs/

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

```