or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

branded-types-validation.mdcollection-codecs.mddate-handling.mdfunctional-programming-types.mdindex.mdjson-handling.mdstring-number-transformations.mdutility-functions-codec-modifiers.md
tile.json

json-handling.mddocs/

0

# JSON Handling

1

2

Comprehensive JSON parsing and validation with proper type definitions for all JSON value types. These codecs provide safe parsing and serialization of JSON data with full type safety.

3

4

## Capabilities

5

6

### JSON Type Definitions

7

8

Complete type definitions for all possible JSON values, enabling type-safe JSON manipulation.

9

10

```typescript { .api }

11

/**

12

* Interface for JSON objects with string keys

13

*/

14

interface JsonRecord {

15

readonly [key: string]: Json;

16

}

17

18

/**

19

* Interface for JSON arrays extending ReadonlyArray

20

*/

21

interface JsonArray extends ReadonlyArray<Json> {}

22

23

/**

24

* Union type representing any valid JSON value

25

* Includes all primitive JSON types and recursive structures

26

*/

27

type Json = boolean | number | string | null | JsonArray | JsonRecord;

28

```

29

30

### JSON Array Codec

31

32

Codec for validating and working with JSON arrays specifically.

33

34

```typescript { .api }

35

/**

36

* Codec for JSON arrays

37

* Validates arrays where all elements are valid JSON values

38

*/

39

const JsonArray: t.Type<JsonArray>;

40

```

41

42

**Usage Examples:**

43

44

```typescript

45

import { JsonArray } from "io-ts-types";

46

47

const result1 = JsonArray.decode([1, "hello", true, null]);

48

// Right([1, "hello", true, null] as JsonArray)

49

50

const result2 = JsonArray.decode([1, [2, 3], { key: "value" }]);

51

// Right([1, [2, 3], { key: "value" }] as JsonArray)

52

53

const result3 = JsonArray.decode([]);

54

// Right([] as JsonArray) - empty array is valid

55

56

const result4 = JsonArray.decode([1, undefined, 3]);

57

// Left([ValidationError]) - undefined is not a valid JSON value

58

59

const result5 = JsonArray.decode("not-an-array");

60

// Left([ValidationError]) - not an array

61

62

// Encoding is identity for valid JSON arrays

63

const encoded = JsonArray.encode([1, "test", null]);

64

// [1, "test", null]

65

```

66

67

### JSON Record Codec

68

69

Codec for validating and working with JSON objects specifically.

70

71

```typescript { .api }

72

/**

73

* Codec for JSON objects (records)

74

* Validates objects where all values are valid JSON values

75

*/

76

const JsonRecord: t.Type<JsonRecord>;

77

```

78

79

**Usage Examples:**

80

81

```typescript

82

import { JsonRecord } from "io-ts-types";

83

84

const result1 = JsonRecord.decode({

85

name: "Alice",

86

age: 25,

87

active: true,

88

metadata: null

89

});

90

// Right({ name: "Alice", age: 25, active: true, metadata: null } as JsonRecord)

91

92

const result2 = JsonRecord.decode({

93

users: [{ id: 1, name: "Bob" }],

94

config: { enabled: true, timeout: 30 }

95

});

96

// Right({ users: [...], config: {...} } as JsonRecord)

97

98

const result3 = JsonRecord.decode({});

99

// Right({} as JsonRecord) - empty object is valid

100

101

const result4 = JsonRecord.decode({

102

valid: "value",

103

invalid: undefined

104

});

105

// Left([ValidationError]) - undefined is not a valid JSON value

106

107

const result5 = JsonRecord.decode([1, 2, 3]);

108

// Left([ValidationError]) - array is not a record

109

110

// Encoding is identity for valid JSON records

111

const encoded = JsonRecord.encode({ key: "value", number: 42 });

112

// { key: "value", number: 42 }

113

```

114

115

### JSON Value Codec

116

117

Codec for any valid JSON value, providing comprehensive JSON validation.

118

119

```typescript { .api }

120

/**

121

* Codec for any valid JSON value

122

* Validates any value that can be represented in JSON

123

*/

124

const Json: t.Type<Json>;

125

```

126

127

**Usage Examples:**

128

129

```typescript

130

import { Json } from "io-ts-types";

131

132

// Primitive JSON values

133

const result1 = Json.decode(42);

134

// Right(42 as Json)

135

136

const result2 = Json.decode("hello");

137

// Right("hello" as Json)

138

139

const result3 = Json.decode(true);

140

// Right(true as Json)

141

142

const result4 = Json.decode(null);

143

// Right(null as Json)

144

145

// Complex JSON structures

146

const result5 = Json.decode({

147

name: "Alice",

148

scores: [95, 87, 92],

149

metadata: {

150

created: "2023-12-25",

151

tags: ["student", "honor-roll"]

152

}

153

});

154

// Right({...} as Json)

155

156

// Invalid JSON values

157

const result6 = Json.decode(undefined);

158

// Left([ValidationError]) - undefined not valid in JSON

159

160

const result7 = Json.decode(Symbol("test"));

161

// Left([ValidationError]) - symbols not valid in JSON

162

163

const result8 = Json.decode(() => {});

164

// Left([ValidationError]) - functions not valid in JSON

165

166

// Encoding is identity for valid JSON

167

const encoded = Json.encode({ key: [1, 2, 3], flag: true });

168

// { key: [1, 2, 3], flag: true }

169

```

170

171

### JSON String Parsing

172

173

Codec that parses JSON strings to Json values and stringifies Json values back to strings.

174

175

```typescript { .api }

176

/**

177

* Codec that parses JSON strings to Json values

178

* Handles JSON.parse() and JSON.stringify() operations safely

179

*/

180

const JsonFromString: t.Type<Json, string, string>;

181

```

182

183

**Usage Examples:**

184

185

```typescript

186

import { JsonFromString } from "io-ts-types";

187

188

// Valid JSON strings

189

const result1 = JsonFromString.decode('{"name": "Alice", "age": 25}');

190

// Right({ name: "Alice", age: 25 } as Json)

191

192

const result2 = JsonFromString.decode('[1, 2, 3, "hello"]');

193

// Right([1, 2, 3, "hello"] as Json)

194

195

const result3 = JsonFromString.decode('"simple string"');

196

// Right("simple string" as Json)

197

198

const result4 = JsonFromString.decode('42');

199

// Right(42 as Json)

200

201

const result5 = JsonFromString.decode('true');

202

// Right(true as Json)

203

204

const result6 = JsonFromString.decode('null');

205

// Right(null as Json)

206

207

// Invalid JSON strings

208

const result7 = JsonFromString.decode('{"invalid": json}');

209

// Left([ValidationError]) - invalid JSON syntax

210

211

const result8 = JsonFromString.decode('undefined');

212

// Left([ValidationError]) - undefined is not valid JSON

213

214

const result9 = JsonFromString.decode('');

215

// Left([ValidationError]) - empty string is not valid JSON

216

217

// Encoding Json back to string

218

const jsonValue = { name: "Bob", items: [1, 2, 3] };

219

const encoded = JsonFromString.encode(jsonValue);

220

// '{"name":"Bob","items":[1,2,3]}' - stringified JSON

221

222

// Round-trip example

223

const originalString = '{"test": true, "count": 42}';

224

const parsed = JsonFromString.decode(originalString);

225

if (parsed._tag === "Right") {

226

const backToString = JsonFromString.encode(parsed.right);

227

// backToString might be formatted differently but semantically equivalent

228

}

229

```

230

231

## Common Usage Patterns

232

233

### API Response Processing

234

235

```typescript

236

import * as t from "io-ts";

237

import { JsonFromString, Json } from "io-ts-types";

238

239

const ApiResponse = t.type({

240

status: t.string,

241

data: Json, // Any JSON data

242

metadata: Json // Any JSON metadata

243

});

244

245

// Process API response with mixed JSON data

246

const responseData = {

247

status: "success",

248

data: {

249

users: [

250

{ id: 1, name: "Alice", active: true },

251

{ id: 2, name: "Bob", active: false }

252

],

253

pagination: { page: 1, total: 100 }

254

},

255

metadata: {

256

timestamp: "2023-12-25T10:30:00Z",

257

version: "1.0",

258

cached: false

259

}

260

};

261

262

const parsed = ApiResponse.decode(responseData);

263

// Right({ status: "success", data: Json, metadata: Json })

264

265

// Safe access to JSON data

266

if (parsed._tag === "Right") {

267

const { data, metadata } = parsed.right;

268

269

// data and metadata are typed as Json, enabling safe manipulation

270

console.log(`API version: ${(metadata as any).version}`);

271

console.log(`User count: ${((data as any).users as any[]).length}`);

272

}

273

```

274

275

### Configuration File Processing

276

277

```typescript

278

import * as t from "io-ts";

279

import { JsonFromString } from "io-ts-types";

280

281

const ConfigFile = t.type({

282

name: t.string,

283

settings: JsonFromString, // JSON string that gets parsed

284

overrides: JsonFromString

285

});

286

287

// Configuration with JSON strings

288

const configData = {

289

name: "MyApp",

290

settings: '{"theme": "dark", "notifications": true, "timeout": 30000}',

291

overrides: '{"debug": true, "logLevel": "verbose"}'

292

};

293

294

const validated = ConfigFile.decode(configData);

295

296

if (validated._tag === "Right") {

297

const config = validated.right;

298

299

// settings and overrides are now parsed JSON objects

300

console.log(`Theme: ${(config.settings as any).theme}`);

301

console.log(`Debug mode: ${(config.overrides as any).debug}`);

302

303

// Can encode back to JSON strings

304

const settingsString = JsonFromString.encode(config.settings);

305

// '{"theme":"dark","notifications":true,"timeout":30000}'

306

}

307

```

308

309

### Dynamic Content Handling

310

311

```typescript

312

import * as t from "io-ts";

313

import { Json, JsonRecord, JsonArray } from "io-ts-types";

314

315

const ContentBlock = t.type({

316

type: t.string,

317

id: t.string,

318

data: Json, // Flexible JSON data

319

attributes: JsonRecord, // Must be a JSON object

320

children: JsonArray // Must be a JSON array

321

});

322

323

const contentData = {

324

type: "article",

325

id: "post_123",

326

data: {

327

title: "Getting Started",

328

body: "Welcome to our platform...",

329

published: true,

330

tags: ["tutorial", "beginner"]

331

},

332

attributes: {

333

author: "Alice",

334

category: "documentation",

335

featured: false

336

},

337

children: [

338

{ type: "paragraph", content: "First paragraph..." },

339

{ type: "image", src: "example.jpg", alt: "Example" }

340

]

341

};

342

343

const validated = ContentBlock.decode(contentData);

344

// All JSON fields are validated for proper JSON structure

345

```

346

347

### Form Data with JSON Fields

348

349

```typescript

350

import * as t from "io-ts";

351

import { JsonFromString, Json } from "io-ts-types";

352

353

const FormSubmission = t.type({

354

userId: t.string,

355

formType: t.string,

356

formData: JsonFromString, // JSON string from form

357

metadata: t.union([JsonFromString, t.null])

358

});

359

360

// Form submission with JSON fields

361

const submission = {

362

userId: "user_123",

363

formType: "contact",

364

formData: '{"name": "Alice", "email": "alice@example.com", "message": "Hello!"}',

365

metadata: '{"source": "website", "referrer": "google.com"}'

366

};

367

368

const validated = FormSubmission.decode(submission);

369

370

if (validated._tag === "Right") {

371

const form = validated.right;

372

373

// formData is now a parsed JSON object

374

const parsedData = form.formData as any;

375

console.log(`Contact from: ${parsedData.name} <${parsedData.email}>`);

376

console.log(`Message: ${parsedData.message}`);

377

378

// metadata is also parsed (or null)

379

if (form.metadata !== null) {

380

const meta = form.metadata as any;

381

console.log(`Source: ${meta.source}, Referrer: ${meta.referrer}`);

382

}

383

}

384

```

385

386

### Database Record with JSON Columns

387

388

```typescript

389

import * as t from "io-ts";

390

import { Json, JsonRecord } from "io-ts-types";

391

392

const DatabaseRecord = t.type({

393

id: t.number,

394

name: t.string,

395

data: Json, // JSON column - any valid JSON

396

settings: JsonRecord, // JSON column - must be object

397

created_at: t.string

398

});

399

400

// Database record with JSON columns

401

const record = {

402

id: 1,

403

name: "User Profile",

404

data: {

405

profile: {

406

avatar: "avatar.jpg",

407

bio: "Software developer",

408

social: {

409

twitter: "@alice_dev",

410

github: "alice-codes"

411

}

412

},

413

preferences: {

414

theme: "dark",

415

notifications: ["email", "push"],

416

privacy: { public: false }

417

}

418

},

419

settings: {

420

language: "en",

421

timezone: "UTC",

422

currency: "USD"

423

},

424

created_at: "2023-12-25T10:30:00Z"

425

};

426

427

const validated = DatabaseRecord.decode(record);

428

// Ensures data is valid JSON and settings is a valid JSON object

429

```

430

431

### API Webhook Payload

432

433

```typescript

434

import * as t from "io-ts";

435

import { Json, JsonFromString } from "io-ts-types";

436

437

const WebhookPayload = t.type({

438

event: t.string,

439

timestamp: t.string,

440

payload: Json, // Event data - any JSON structure

441

signature: t.string,

442

raw: JsonFromString // Raw payload string for signature verification

443

});

444

445

const webhookData = {

446

event: "user.created",

447

timestamp: "2023-12-25T10:30:00Z",

448

payload: {

449

user: {

450

id: 123,

451

email: "new-user@example.com",

452

created_at: "2023-12-25T10:30:00Z"

453

},

454

metadata: {

455

source: "registration_form",

456

ip_address: "192.168.1.1"

457

}

458

},

459

signature: "sha256=abc123...",

460

raw: '{"user":{"id":123,"email":"new-user@example.com","created_at":"2023-12-25T10:30:00Z"},"metadata":{"source":"registration_form","ip_address":"192.168.1.1"}}'

461

};

462

463

const validated = WebhookPayload.decode(webhookData);

464

// Validates event payload structure and parses raw JSON string

465

```