or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdformatters-types.mdindex.mdmessage-formatting.md
tile.json

error-handling.mddocs/

0

# Error Handling

1

2

Comprehensive error system for handling various formatting failures including missing values, invalid types, and missing Intl APIs.

3

4

## Capabilities

5

6

### ErrorCode Enum

7

8

Defines the types of errors that can occur during message formatting.

9

10

```typescript { .api }

11

/**

12

* Error codes for different types of formatting failures

13

*/

14

enum ErrorCode {

15

/** When a placeholder has no corresponding value provided */

16

MISSING_VALUE = 'MISSING_VALUE',

17

/** When a provided value is invalid for the placeholder type */

18

INVALID_VALUE = 'INVALID_VALUE',

19

/** When a required Intl API is not available in the environment */

20

MISSING_INTL_API = 'MISSING_INTL_API'

21

}

22

```

23

24

### FormatError Class

25

26

Base error class for all formatting-related errors.

27

28

```typescript { .api }

29

/**

30

* Base class for formatting errors

31

*/

32

class FormatError extends Error {

33

/** Error code identifying the type of error */

34

readonly code: ErrorCode;

35

/** Original message string being formatted (if available) */

36

readonly originalMessage: string | undefined;

37

38

/**

39

* Create a new FormatError

40

* @param msg - Error message

41

* @param code - Error code

42

* @param originalMessage - Original message string being formatted

43

*/

44

constructor(msg: string, code: ErrorCode, originalMessage?: string);

45

46

/**

47

* Custom string representation

48

* @returns Formatted error string with code

49

*/

50

toString(): string;

51

}

52

```

53

54

**Usage Examples:**

55

56

```typescript

57

import { FormatError, ErrorCode } from "intl-messageformat";

58

59

try {

60

const msg = new IntlMessageFormat('Hello {name}!', 'en-US');

61

msg.format({}); // Missing 'name' value

62

} catch (error) {

63

if (error instanceof FormatError) {

64

console.log(error.code); // ErrorCode.MISSING_VALUE

65

console.log(error.originalMessage); // 'Hello {name}!'

66

console.log(error.toString()); // "[formatjs Error: MISSING_VALUE] ..."

67

}

68

}

69

```

70

71

### MissingValueError Class

72

73

Thrown when a placeholder in the message has no corresponding value in the provided data.

74

75

```typescript { .api }

76

/**

77

* Error thrown when a required placeholder value is missing

78

*/

79

class MissingValueError extends FormatError {

80

/**

81

* Create a new MissingValueError

82

* @param variableId - Name of the missing variable

83

* @param originalMessage - Original message string being formatted

84

*/

85

constructor(variableId: string, originalMessage?: string);

86

}

87

```

88

89

**Usage Examples:**

90

91

```typescript

92

import IntlMessageFormat from "intl-messageformat";

93

94

try {

95

const msg = new IntlMessageFormat('Welcome {firstName} {lastName}!', 'en-US');

96

msg.format({ firstName: 'John' }); // Missing lastName

97

} catch (error) {

98

console.log(error.message);

99

// "The intl string context variable "lastName" was not provided to the string "Welcome {firstName} {lastName}!""

100

}

101

```

102

103

### InvalidValueError Class

104

105

Thrown when a value provided for a placeholder is not valid for that placeholder type (e.g., wrong option in a select statement).

106

107

```typescript { .api }

108

/**

109

* Error thrown when a provided value is invalid for the placeholder

110

*/

111

class InvalidValueError extends FormatError {

112

/**

113

* Create a new InvalidValueError

114

* @param variableId - Name of the variable with invalid value

115

* @param value - The invalid value that was provided

116

* @param options - Valid options for this variable

117

* @param originalMessage - Original message string being formatted

118

*/

119

constructor(

120

variableId: string,

121

value: any,

122

options: string[],

123

originalMessage?: string

124

);

125

}

126

```

127

128

**Usage Examples:**

129

130

```typescript

131

import IntlMessageFormat from "intl-messageformat";

132

133

try {

134

const msg = new IntlMessageFormat(

135

'{status, select, active {Active} inactive {Inactive} other {Unknown}}',

136

'en-US'

137

);

138

msg.format({ status: 'pending' }); // 'pending' not in options

139

} catch (error) {

140

console.log(error.message);

141

// 'Invalid values for "status": "pending". Options are "active", "inactive", "other"'

142

}

143

```

144

145

### InvalidValueTypeError Class

146

147

Thrown when a value is of the wrong type for a placeholder (e.g., providing a string when a function is expected for XML tags).

148

149

```typescript { .api }

150

/**

151

* Error thrown when a value has the wrong type for the placeholder

152

*/

153

class InvalidValueTypeError extends FormatError {

154

/**

155

* Create a new InvalidValueTypeError

156

* @param value - The variable name with wrong type

157

* @param type - The expected type

158

* @param originalMessage - Original message string being formatted

159

*/

160

constructor(value: any, type: string, originalMessage?: string);

161

}

162

```

163

164

**Usage Examples:**

165

166

```typescript

167

import IntlMessageFormat from "intl-messageformat";

168

169

try {

170

const msg = new IntlMessageFormat(

171

'Click <link>here</link> to continue.',

172

'en-US'

173

);

174

msg.format({ link: 'not-a-function' }); // Should be a function

175

} catch (error) {

176

console.log(error.message);

177

// 'Value for "not-a-function" must be of type function'

178

}

179

```

180

181

## Error Handling Patterns

182

183

### Basic Error Handling

184

185

```typescript

186

import IntlMessageFormat, { FormatError, ErrorCode } from "intl-messageformat";

187

188

function safeFormat(messageString: string, values: Record<string, any>, locale = 'en-US') {

189

try {

190

const msg = new IntlMessageFormat(messageString, locale);

191

return msg.format(values);

192

} catch (error) {

193

if (error instanceof FormatError) {

194

switch (error.code) {

195

case ErrorCode.MISSING_VALUE:

196

console.warn('Missing value:', error.message);

197

return messageString; // Fallback to original

198

case ErrorCode.INVALID_VALUE:

199

console.warn('Invalid value:', error.message);

200

return messageString;

201

case ErrorCode.MISSING_INTL_API:

202

console.error('Missing Intl API:', error.message);

203

return messageString;

204

default:

205

console.error('Format error:', error.message);

206

return messageString;

207

}

208

}

209

throw error; // Re-throw non-format errors

210

}

211

}

212

```

213

214

### Validation Before Formatting

215

216

```typescript

217

function validateMessageValues(

218

messageString: string,

219

values: Record<string, any>,

220

locale = 'en-US'

221

): { isValid: boolean; errors: string[] } {

222

const errors: string[] = [];

223

224

try {

225

const msg = new IntlMessageFormat(messageString, locale);

226

msg.format(values);

227

return { isValid: true, errors: [] };

228

} catch (error) {

229

if (error instanceof FormatError) {

230

errors.push(error.message);

231

return { isValid: false, errors };

232

}

233

throw error;

234

}

235

}

236

237

// Usage

238

const validation = validateMessageValues(

239

'Hello {name}, you have {count, plural, one {# message} other {# messages}}.',

240

{ name: 'Alice' } // Missing count

241

);

242

if (!validation.isValid) {

243

console.log('Validation errors:', validation.errors);

244

}

245

```

246

247

### Development vs Production Error Handling

248

249

```typescript

250

const isDevelopment = process.env.NODE_ENV === 'development';

251

252

function formatMessage(messageString: string, values: Record<string, any>) {

253

try {

254

const msg = new IntlMessageFormat(messageString, 'en-US');

255

return msg.format(values);

256

} catch (error) {

257

if (isDevelopment) {

258

// In development, show detailed errors

259

console.error('Message formatting failed:', {

260

message: messageString,

261

values,

262

error: error.message

263

});

264

return `[FORMAT ERROR: ${error.message}]`;

265

} else {

266

// In production, fail silently with fallback

267

console.warn('Message formatting failed silently');

268

return messageString;

269

}

270

}

271

}

272

```

273

274

## Error Prevention

275

276

### Type-Safe Value Objects

277

278

```typescript

279

// Define interfaces for your message values

280

interface UserMessage {

281

name: string;

282

count: number;

283

status: 'active' | 'inactive';

284

}

285

286

function formatUserMessage(values: UserMessage) {

287

const msg = new IntlMessageFormat(

288

'Hello {name}! You have {count, number} items. Status: {status, select, active {Active} inactive {Inactive} other {Unknown}}',

289

'en-US'

290

);

291

return msg.format(values);

292

}

293

294

// This will catch type errors at compile time

295

formatUserMessage({

296

name: 'Alice',

297

count: 5,

298

status: 'active' // TypeScript ensures this is valid

299

});

300

```

301

302

### Message Validation Utility

303

304

```typescript

305

class MessageValidator {

306

static validatePlaceholders(

307

messageString: string,

308

providedValues: Record<string, any>

309

): { missing: string[]; extra: string[] } {

310

// Extract placeholders from message (simplified)

311

const placeholders = messageString.match(/{([^}]+)}/g)?.map(

312

match => match.slice(1, -1).split(',')[0].trim()

313

) || [];

314

315

const provided = Object.keys(providedValues);

316

const missing = placeholders.filter(p => !provided.includes(p));

317

const extra = provided.filter(p => !placeholders.includes(p));

318

319

return { missing, extra };

320

}

321

}

322

323

// Usage

324

const validation = MessageValidator.validatePlaceholders(

325

'Hello {name}!',

326

{ name: 'Alice', age: 25 }

327

);

328

console.log(validation); // { missing: [], extra: ['age'] }

329

```