or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

codec.mdcombinators.mdcore-types.mddecoder.mdencoder.mdindex.mdinfrastructure.mdprimitives.mdrefinement.mdreporters.mdschema.mdtask-decoder.mdvalidation.md
tile.json

decoder.mddocs/

0

# Modern Decoder API

1

2

Experimental modern decoder system with enhanced error reporting and functional composition patterns.

3

4

## Capabilities

5

6

### Decoder Interface

7

8

The core Decoder interface with functional programming patterns.

9

10

```typescript { .api }

11

/**

12

* Kleisli decoder interface for functional composition

13

* @template I - Input type

14

* @template A - Output type after successful decoding

15

*/

16

interface Decoder<I, A> {

17

readonly decode: (i: I) => Either<DecodeError, A>;

18

}

19

20

/** Decoder error type using FreeSemigroup for error accumulation */

21

type DecodeError = FreeSemigroup<DE.DecodeError<string>>;

22

```

23

24

### Error Handling

25

26

Enhanced error system with detailed decode error information.

27

28

```typescript { .api }

29

/**

30

* Create a decode error

31

* @param actual - The actual value that failed

32

* @param message - Error message

33

*/

34

function error(actual: unknown, message: string): DecodeError;

35

36

/**

37

* Create a successful decoder result

38

* @param value - The successful value

39

*/

40

function success<A>(value: A): Either<DecodeError, A>;

41

42

/**

43

* Create a failed decoder result

44

* @param error - The decode error

45

*/

46

function failure<A>(error: DecodeError): Either<DecodeError, A>;

47

```

48

49

### Constructor Functions

50

51

Functions for creating decoders from various sources.

52

53

```typescript { .api }

54

/**

55

* Create decoder from a refinement function

56

* @param refinement - Type refinement function

57

* @param expected - Expected type description

58

*/

59

function fromRefinement<I, A>(

60

refinement: Refinement<I, A>,

61

expected: string

62

): Decoder<I, A>;

63

64

/**

65

* Create decoder from a Guard

66

* @param guard - Guard instance

67

* @param expected - Expected type description

68

*/

69

function fromGuard<I, A>(guard: G.Guard<I, A>, expected: string): Decoder<I, A>;

70

71

/**

72

* Create a literal value decoder

73

* @param value - The literal value to match

74

*/

75

function literal<A extends Literal>(value: A): Decoder<unknown, A>;

76

77

type Literal = string | number | boolean | null;

78

```

79

80

### Primitive Decoders

81

82

Built-in decoders for basic types.

83

84

```typescript { .api }

85

/** String decoder */

86

const string: Decoder<unknown, string>;

87

88

/** Number decoder */

89

const number: Decoder<unknown, number>;

90

91

/** Boolean decoder */

92

const boolean: Decoder<unknown, boolean>;

93

94

/** Unknown array decoder */

95

const UnknownArray: Decoder<unknown, Array<unknown>>;

96

97

/** Unknown record decoder */

98

const UnknownRecord: Decoder<unknown, Record<string, unknown>>;

99

```

100

101

**Usage Examples:**

102

103

```typescript

104

import * as D from "io-ts/Decoder";

105

import { pipe } from "fp-ts/function";

106

import { fold } from "fp-ts/Either";

107

108

// Basic decoding

109

const result = D.string.decode("hello");

110

pipe(

111

result,

112

fold(

113

(error) => console.error("Decode failed:", D.draw(error)),

114

(value) => console.log("Success:", value)

115

)

116

);

117

118

// Literal decoding

119

const Status = D.literal('active');

120

const statusResult = Status.decode('active');

121

// result: Right('active')

122

```

123

124

### Combinator Functions

125

126

Functions for composing complex decoders.

127

128

```typescript { .api }

129

/**

130

* Create struct decoder from property decoders with typed inputs

131

* @param properties - Object mapping property names to decoders

132

*/

133

function fromStruct<P extends Record<string, Decoder<any, any>>>(

134

properties: P

135

): Decoder<{ [K in keyof P]: InputOf<P[K]> }, { [K in keyof P]: TypeOf<P[K]> }>;

136

137

/**

138

* Create struct decoder from property decoders (from unknown input)

139

* @param properties - Object mapping property names to decoders

140

*/

141

function struct<A>(properties: { [K in keyof A]: Decoder<unknown, A[K]> }): Decoder<unknown, A>;

142

143

/**

144

* Create partial struct decoder with typed inputs where all properties are optional

145

* @param properties - Object mapping property names to decoders

146

*/

147

function fromPartial<P extends Record<string, Decoder<any, any>>>(

148

properties: P

149

): Decoder<Partial<{ [K in keyof P]: InputOf<P[K]> }>, Partial<{ [K in keyof P]: TypeOf<P[K]> }>>;

150

151

/**

152

* Create partial struct decoder where all properties are optional

153

* @param properties - Object mapping property names to decoders

154

*/

155

function partial<A>(properties: { [K in keyof A]: Decoder<unknown, A[K]> }): Decoder<unknown, Partial<A>>;

156

157

/**

158

* Create array decoder with typed inputs

159

* @param item - Decoder for array elements

160

*/

161

function fromArray<I, A>(item: Decoder<I, A>): Decoder<Array<I>, Array<A>>;

162

163

/**

164

* Create array decoder with element decoder

165

* @param item - Decoder for array elements

166

*/

167

function array<A>(item: Decoder<unknown, A>): Decoder<unknown, Array<A>>;

168

169

/**

170

* Create record decoder with typed inputs

171

* @param codomain - Decoder for record values

172

*/

173

function fromRecord<I, A>(codomain: Decoder<I, A>): Decoder<Record<string, I>, Record<string, A>>;

174

175

/**

176

* Create record decoder with value decoder

177

* @param codomain - Decoder for record values

178

*/

179

function record<A>(codomain: Decoder<unknown, A>): Decoder<unknown, Record<string, A>>;

180

181

/**

182

* Create tuple decoder with typed inputs

183

* @param components - Array of decoders for each tuple position

184

*/

185

function fromTuple<C extends ReadonlyArray<Decoder<any, any>>>(

186

...components: C

187

): Decoder<{ [K in keyof C]: InputOf<C[K]> }, { [K in keyof C]: TypeOf<C[K]> }>;

188

189

/**

190

* Create tuple decoder with component decoders

191

* @param components - Array of decoders for each tuple position

192

*/

193

function tuple<A extends ReadonlyArray<unknown>>(

194

...components: { [K in keyof A]: Decoder<unknown, A[K]> }

195

): Decoder<unknown, A>;

196

197

/**

198

* Create union decoder that tries multiple decoders

199

* @param members - Array of decoder alternatives

200

*/

201

function union<MS extends [Decoder<unknown, any>, ...Array<Decoder<unknown, any>>]>(

202

...members: MS

203

): Decoder<unknown, TypeOf<MS[number]>>;

204

205

/**

206

* Create intersection decoder that applies all decoders

207

* @param right - Second decoder to intersect

208

*/

209

function intersect<B>(right: Decoder<unknown, B>): <A>(left: Decoder<unknown, A>) => Decoder<unknown, A & B>;

210

211

/**

212

* Create tagged union decoder from member decoders with typed inputs

213

* @param tag - The discriminator property key

214

*/

215

function fromSum<T extends string>(

216

tag: T

217

): <MS extends Record<string, Decoder<any, any>>>(

218

members: MS

219

) => Decoder<InputOf<MS[keyof MS]>, TypeOf<MS[keyof MS]>>;

220

221

/**

222

* Create tagged union decoder from member decoders

223

* @param tag - The discriminator property key

224

*/

225

function sum<T extends string>(

226

tag: T

227

): <A>(members: { [K in keyof A]: Decoder<unknown, A[K] & Record<T, K>> }) => Decoder<unknown, A[keyof A]>;

228

```

229

230

### Deprecated Functions

231

232

The following functions are deprecated and should be avoided in new code:

233

234

```typescript { .api }

235

/**

236

* @deprecated Use fromStruct instead

237

*/

238

const fromType: typeof fromStruct;

239

240

/**

241

* @deprecated Use struct instead

242

*/

243

const type: typeof struct;

244

```

245

246

**Usage Examples:**

247

248

```typescript

249

import * as D from "io-ts/Decoder";

250

251

// Struct decoder

252

const User = D.struct({

253

name: D.string,

254

age: D.number,

255

email: D.string

256

});

257

258

const userData = User.decode({

259

name: "Alice",

260

age: 30,

261

email: "alice@example.com"

262

});

263

264

// Array decoder

265

const Numbers = D.array(D.number);

266

const numbersResult = Numbers.decode([1, 2, 3]);

267

268

// Union decoder

269

const StringOrNumber = D.union(D.string, D.number);

270

const unionResult1 = StringOrNumber.decode("hello");

271

const unionResult2 = StringOrNumber.decode(42);

272

273

// Tuple decoder

274

const Coordinate = D.tuple(D.number, D.number);

275

const coordResult = Coordinate.decode([10, 20]);

276

277

// Tagged union decoder

278

const Shape = D.sum('type')({

279

circle: D.struct({

280

type: D.literal('circle'),

281

radius: D.number

282

}),

283

rectangle: D.struct({

284

type: D.literal('rectangle'),

285

width: D.number,

286

height: D.number

287

})

288

});

289

290

const shapeResult = Shape.decode({ type: 'circle', radius: 5 });

291

```

292

293

### Advanced Combinators

294

295

More sophisticated decoder combinators for complex scenarios.

296

297

```typescript { .api }

298

/**

299

* Add custom error message to decoder failures

300

* @param message - Custom error message

301

*/

302

function withMessage<I>(message: string): <A>(decoder: Decoder<I, A>) => Decoder<I, A>;

303

304

/**

305

* Refine a decoder with additional predicate

306

* @param predicate - Predicate function for refinement

307

* @param expected - Expected type description

308

*/

309

function refine<A, B extends A>(

310

predicate: Refinement<A, B>,

311

expected: string

312

): (decoder: Decoder<unknown, A>) => Decoder<unknown, B>;

313

314

/**

315

* Parse decoder result with custom function

316

* @param parser - Function to transform decoded value (returns Either<DecodeError, B>)

317

*/

318

function parse<A, B>(

319

parser: (a: A) => Either<DecodeError, B>

320

): <I>(from: Decoder<I, A>) => Decoder<I, B>;

321

322

/**

323

* Make decoder nullable (accepts null values)

324

* @param decoder - Base decoder to make nullable

325

*/

326

function nullable<A>(decoder: Decoder<unknown, A>): Decoder<unknown, A | null>;

327

328

/**

329

* Create lazy decoder for recursive types

330

* @param f - Function that returns the decoder

331

*/

332

function lazy<A>(f: () => Decoder<unknown, A>): Decoder<unknown, A>;

333

334

/**

335

* Map left side with input for better error messages

336

* @param f - Function to transform errors with input context

337

*/

338

function mapLeftWithInput<I>(

339

f: (input: I, error: DecodeError) => DecodeError

340

): <A>(decoder: Decoder<I, A>) => Decoder<I, A>;

341

```

342

343

**Usage Examples:**

344

345

```typescript

346

import * as D from "io-ts/Decoder";

347

import { pipe } from "fp-ts/function";

348

349

// Custom error messages

350

const EmailWithMessage = pipe(

351

D.string,

352

D.refine((s): s is string => /\S+@\S+\.\S+/.test(s), 'valid email'),

353

D.withMessage('Please provide a valid email address')

354

);

355

356

// Parse transformation

357

const StringToNumber = pipe(

358

D.string,

359

D.parse((s) => {

360

const n = parseFloat(s);

361

return isNaN(n) ? left(`Cannot parse "${s}" as number`) : right(n);

362

})

363

);

364

365

// Nullable decoder

366

const OptionalName = D.nullable(D.string);

367

const result1 = OptionalName.decode("Alice"); // Right("Alice")

368

const result2 = OptionalName.decode(null); // Right(null)

369

370

// Recursive decoder

371

interface Category {

372

name: string;

373

subcategories: Category[];

374

}

375

376

const Category: D.Decoder<unknown, Category> = D.lazy(() =>

377

D.struct({

378

name: D.string,

379

subcategories: D.array(Category)

380

})

381

);

382

```

383

384

### Functional Composition

385

386

Functional programming utilities for decoder composition.

387

388

```typescript { .api }

389

/**

390

* Map over successful decoder results

391

* @param f - Transformation function

392

*/

393

function map<A, B>(f: (a: A) => B): (decoder: Decoder<unknown, A>) => Decoder<unknown, B>;

394

395

/**

396

* Alternative decoder (try second if first fails)

397

* @param that - Alternative decoder

398

*/

399

function alt<A>(that: () => Decoder<unknown, A>): (decoder: Decoder<unknown, A>) => Decoder<unknown, A>;

400

401

/**

402

* Compose two decoders

403

* @param to - Target decoder

404

*/

405

function compose<A, B>(to: Decoder<A, B>): (from: Decoder<unknown, A>) => Decoder<unknown, B>;

406

407

/**

408

* Identity decoder

409

*/

410

function id<A>(): Decoder<A, A>;

411

```

412

413

### Type Utilities and Instances

414

415

Type extraction and functional programming instances.

416

417

```typescript { .api }

418

/** Extract input type from decoder */

419

type InputOf<D> = D extends Decoder<infer I, any> ? I : never;

420

421

/** Extract output type from decoder */

422

type TypeOf<D> = D extends Decoder<any, infer A> ? A : never;

423

424

/** Module URI for HKT support */

425

const URI = 'io-ts/Decoder';

426

427

/** Functor instance */

428

const Functor: Functor1<typeof URI>;

429

430

/** Alt instance */

431

const Alt: Alt1<typeof URI>;

432

433

/** Category instance */

434

const Category: Category1<typeof URI>;

435

```

436

437

### Error Formatting

438

439

Utilities for formatting and displaying decode errors.

440

441

```typescript { .api }

442

/**

443

* Draw decode error as readable string

444

* @param error - The decode error to format

445

*/

446

function draw(error: DecodeError): string;

447

448

/**

449

* Format Either result as string

450

* @param result - Either result to stringify

451

*/

452

function stringify<A>(result: Either<DecodeError, A>): string;

453

```

454

455

**Usage Example:**

456

457

```typescript

458

import * as D from "io-ts/Decoder";

459

460

const User = D.struct({

461

name: D.string,

462

age: D.number

463

});

464

465

const result = User.decode({ name: 123, age: "thirty" });

466

467

if (result._tag === "Left") {

468

console.log("Formatted error:");

469

console.log(D.draw(result.left));

470

471

console.log("Stringified result:");

472

console.log(D.stringify(result));

473

}

474

```

475

476

## Advanced Usage Patterns

477

478

### Complex Validation Pipeline

479

480

```typescript

481

import * as D from "io-ts/Decoder";

482

import { pipe } from "fp-ts/function";

483

import { fold } from "fp-ts/Either";

484

485

const UserData = pipe(

486

D.struct({

487

name: D.string,

488

email: D.string,

489

age: D.number

490

}),

491

D.refine(

492

(user): user is typeof user => user.age >= 18,

493

'adult user'

494

),

495

D.withMessage('User must be an adult with valid contact info')

496

);

497

498

const processUser = (input: unknown) =>

499

pipe(

500

UserData.decode(input),

501

fold(

502

(error) => ({

503

success: false,

504

error: D.draw(error)

505

}),

506

(user) => ({

507

success: true,

508

user: {

509

...user,

510

displayName: user.name.toUpperCase()

511

}

512

})

513

)

514

);

515

```

516

517

### Tagged Union Decoding

518

519

```typescript

520

import * as D from "io-ts/Decoder";

521

522

const Shape = D.union(

523

D.struct({

524

type: D.literal('circle'),

525

radius: D.number

526

}),

527

D.struct({

528

type: D.literal('rectangle'),

529

width: D.number,

530

height: D.number

531

}),

532

D.struct({

533

type: D.literal('triangle'),

534

base: D.number,

535

height: D.number

536

})

537

);

538

539

const shapes = [

540

{ type: 'circle', radius: 5 },

541

{ type: 'rectangle', width: 10, height: 20 },

542

{ type: 'triangle', base: 8, height: 12 }

543

];

544

545

shapes.forEach(shape => {

546

const result = Shape.decode(shape);

547

if (result._tag === 'Right') {

548

console.log('Valid shape:', result.right);

549

}

550

});

551

```