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

encoder.mddocs/

0

# Encoding System

1

2

Experimental encoding system for transforming data between different representations.

3

4

## Capabilities

5

6

### Encoder Interface

7

8

The core Encoder interface for data transformation.

9

10

```typescript { .api }

11

/**

12

* Encoder interface for transforming data to different representations

13

* @template O - Output type after encoding

14

* @template A - Input type to encode

15

*/

16

interface Encoder<O, A> {

17

readonly encode: (a: A) => O;

18

}

19

```

20

21

### Combinator Functions

22

23

Functions for creating and composing encoders.

24

25

```typescript { .api }

26

/**

27

* Create struct encoder from property encoders

28

* @param encoders - Object mapping property names to encoders

29

*/

30

function struct<P>(encoders: { [K in keyof P]: Encoder<P[K], P[K]> }): Encoder<P, P>;

31

32

/**

33

* Create partial struct encoder where properties may be undefined

34

* @param encoders - Object mapping property names to encoders

35

*/

36

function partial<P>(encoders: { [K in keyof P]: Encoder<P[K], P[K]> }): Encoder<Partial<P>, Partial<P>>;

37

38

/**

39

* Create array encoder with element encoder

40

* @param item - Encoder for array elements

41

*/

42

function array<O, A>(item: Encoder<O, A>): Encoder<Array<O>, Array<A>>;

43

44

/**

45

* Create record encoder with value encoder

46

* @param codomain - Encoder for record values

47

*/

48

function record<O, A>(codomain: Encoder<O, A>): Encoder<Record<string, O>, Record<string, A>>;

49

50

/**

51

* Create tuple encoder with component encoders

52

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

53

*/

54

function tuple<C extends ReadonlyArray<Encoder<any, any>>>(

55

...components: C

56

): Encoder<{ [K in keyof C]: OutputOf<C[K]> }, { [K in keyof C]: TypeOf<C[K]> }>;

57

58

/**

59

* Create sum encoder for discriminated unions

60

* @param tag - Discriminant property name

61

*/

62

function sum<T extends string>(tag: T): <MS extends Record<string, Encoder<any, any>>>(

63

members: MS

64

) => Encoder<OutputOf<MS[keyof MS]>, TypeOf<MS[keyof MS]>>;

65

66

/**

67

* Make encoder nullable

68

* @param encoder - Base encoder to make nullable

69

*/

70

function nullable<O, A>(encoder: Encoder<O, A>): Encoder<O | null, A | null>;

71

72

/**

73

* Create lazy encoder for recursive types

74

* @param f - Function that returns the encoder

75

*/

76

function lazy<O, A>(f: () => Encoder<O, A>): Encoder<O, A>;

77

78

/**

79

* Make encoder readonly

80

* @param encoder - Base encoder to make readonly

81

*/

82

function readonly<O, A>(encoder: Encoder<O, A>): Encoder<Readonly<O>, Readonly<A>>;

83

84

/**

85

* Intersect two encoders

86

* @param right - Second encoder to intersect

87

*/

88

function intersect<P, B>(

89

right: Encoder<P, B>

90

): <O, A>(left: Encoder<O, A>) => Encoder<O & P, A & B>;

91

```

92

93

**Usage Examples:**

94

95

```typescript

96

import * as E from "io-ts/Encoder";

97

98

// Struct encoder

99

const UserEncoder = E.struct({

100

name: E.id<string>(),

101

age: E.id<number>(),

102

email: E.id<string>()

103

});

104

105

// Array encoder

106

const NumbersEncoder = E.array(E.id<number>());

107

108

// Custom encoder that transforms dates to ISO strings

109

const DateToStringEncoder: E.Encoder<string, Date> = {

110

encode: (date: Date) => date.toISOString()

111

};

112

113

// Compose encoders

114

const TimestampedDataEncoder = E.struct({

115

data: E.id<string>(),

116

timestamp: DateToStringEncoder

117

});

118

119

const result = TimestampedDataEncoder.encode({

120

data: "hello",

121

timestamp: new Date("2023-01-01")

122

});

123

// result: { data: "hello", timestamp: "2023-01-01T00:00:00.000Z" }

124

```

125

126

### Functional Composition

127

128

Functional programming utilities for encoder composition.

129

130

```typescript { .api }

131

/**

132

* Contramap over encoder (transform input before encoding)

133

* @param f - Function to transform input

134

*/

135

function contramap<A, B>(f: (b: B) => A): <O>(encoder: Encoder<O, A>) => Encoder<O, B>;

136

137

/**

138

* Compose two encoders

139

* @param to - Target encoder

140

*/

141

function compose<E, A>(to: Encoder<E, A>): <O>(from: Encoder<A, O>) => Encoder<E, O>;

142

143

/**

144

* Identity encoder

145

*/

146

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

147

```

148

149

**Usage Examples:**

150

151

```typescript

152

import * as E from "io-ts/Encoder";

153

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

154

155

// Contramap example: encode Person as string representation

156

interface Person {

157

firstName: string;

158

lastName: string;

159

age: number;

160

}

161

162

const PersonToStringEncoder = pipe(

163

E.id<string>(),

164

E.contramap((person: Person) =>

165

`${person.firstName} ${person.lastName} (${person.age})`

166

)

167

);

168

169

const person: Person = {

170

firstName: "Alice",

171

lastName: "Smith",

172

age: 30

173

};

174

175

const encoded = PersonToStringEncoder.encode(person);

176

// result: "Alice Smith (30)"

177

178

// Compose encoders

179

const NumberToStringEncoder = pipe(

180

E.id<string>(),

181

E.contramap(String)

182

);

183

184

const result = NumberToStringEncoder.encode(42);

185

// result: "42"

186

```

187

188

### Type Utilities

189

190

Type extraction utilities for encoders.

191

192

```typescript { .api }

193

/** Extract output type from encoder */

194

type OutputOf<E> = E extends Encoder<infer O, any> ? O : never;

195

196

/** Extract input type from encoder */

197

type TypeOf<E> = E extends Encoder<any, infer A> ? A : never;

198

```

199

200

### Functional Programming Support

201

202

Instances for functional programming patterns.

203

204

```typescript { .api }

205

/** Module URI for HKT support */

206

const URI = 'io-ts/Encoder';

207

208

/** Contravariant functor instance */

209

const Contravariant: Contravariant1<typeof URI>;

210

211

/** Category instance */

212

const Category: Category1<typeof URI>;

213

```

214

215

## Advanced Usage Patterns

216

217

### Data Transformation Pipeline

218

219

```typescript

220

import * as E from "io-ts/Encoder";

221

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

222

223

// Transform complex objects for API serialization

224

interface User {

225

id: number;

226

profile: {

227

firstName: string;

228

lastName: string;

229

birthDate: Date;

230

};

231

preferences: {

232

theme: 'light' | 'dark';

233

notifications: boolean;

234

};

235

}

236

237

interface UserApiFormat {

238

id: number;

239

fullName: string;

240

birthYear: number;

241

theme: string;

242

notificationsEnabled: boolean;

243

}

244

245

const UserToApiEncoder: E.Encoder<UserApiFormat, User> = {

246

encode: (user: User) => ({

247

id: user.id,

248

fullName: `${user.profile.firstName} ${user.profile.lastName}`,

249

birthYear: user.profile.birthDate.getFullYear(),

250

theme: user.preferences.theme,

251

notificationsEnabled: user.preferences.notifications

252

})

253

};

254

255

const user: User = {

256

id: 123,

257

profile: {

258

firstName: "Alice",

259

lastName: "Johnson",

260

birthDate: new Date("1990-05-15")

261

},

262

preferences: {

263

theme: 'dark',

264

notifications: true

265

}

266

};

267

268

const apiFormat = UserToApiEncoder.encode(user);

269

// result: {

270

// id: 123,

271

// fullName: "Alice Johnson",

272

// birthYear: 1990,

273

// theme: "dark",

274

// notificationsEnabled: true

275

// }

276

```

277

278

### Database Entity Encoding

279

280

```typescript

281

import * as E from "io-ts/Encoder";

282

283

// Encode domain objects for database storage

284

interface Product {

285

id: string;

286

name: string;

287

price: number;

288

categories: string[];

289

metadata: Record<string, unknown>;

290

createdAt: Date;

291

updatedAt: Date;

292

}

293

294

interface ProductRow {

295

id: string;

296

name: string;

297

price_cents: number;

298

categories_json: string;

299

metadata_json: string;

300

created_at: string;

301

updated_at: string;

302

}

303

304

const ProductToRowEncoder: E.Encoder<ProductRow, Product> = {

305

encode: (product: Product) => ({

306

id: product.id,

307

name: product.name,

308

price_cents: Math.round(product.price * 100),

309

categories_json: JSON.stringify(product.categories),

310

metadata_json: JSON.stringify(product.metadata),

311

created_at: product.createdAt.toISOString(),

312

updated_at: product.updatedAt.toISOString()

313

})

314

};

315

316

const product: Product = {

317

id: "prod-123",

318

name: "Laptop",

319

price: 999.99,

320

categories: ["electronics", "computers"],

321

metadata: { brand: "TechCorp", model: "X1" },

322

createdAt: new Date("2023-01-01"),

323

updatedAt: new Date("2023-01-15")

324

};

325

326

const dbRow = ProductToRowEncoder.encode(product);

327

```

328

329

### Format Conversion

330

331

```typescript

332

import * as E from "io-ts/Encoder";

333

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

334

335

// Convert between different date/time formats

336

const IsoDateEncoder = pipe(

337

E.id<string>(),

338

E.contramap((date: Date) => date.toISOString())

339

);

340

341

const UnixTimestampEncoder = pipe(

342

E.id<number>(),

343

E.contramap((date: Date) => Math.floor(date.getTime() / 1000))

344

);

345

346

const LocaleDateEncoder = pipe(

347

E.id<string>(),

348

E.contramap((date: Date) => date.toLocaleDateString())

349

);

350

351

// Create different representations of the same data

352

const now = new Date();

353

354

const formats = {

355

iso: IsoDateEncoder.encode(now),

356

unix: UnixTimestampEncoder.encode(now),

357

locale: LocaleDateEncoder.encode(now)

358

};

359

360

console.log(formats);

361

// Output: {

362

// iso: "2023-01-01T12:00:00.000Z",

363

// unix: 1672574400,

364

// locale: "1/1/2023"

365

// }

366

```

367

368

### Configuration Serialization

369

370

```typescript

371

import * as E from "io-ts/Encoder";

372

373

// Encode configuration objects for storage or transmission

374

interface AppConfig {

375

database: {

376

host: string;

377

port: number;

378

ssl: boolean;

379

};

380

features: {

381

enableAnalytics?: boolean;

382

maxConnections?: number;

383

};

384

environment: 'development' | 'staging' | 'production';

385

}

386

387

interface ConfigFile {

388

database_url: string;

389

analytics_enabled: boolean;

390

max_connections: number;

391

env: string;

392

}

393

394

const ConfigToFileEncoder: E.Encoder<ConfigFile, AppConfig> = {

395

encode: (config: AppConfig) => ({

396

database_url: `${config.database.ssl ? 'postgresql' : 'postgres'}://${config.database.host}:${config.database.port}`,

397

analytics_enabled: config.features.enableAnalytics ?? false,

398

max_connections: config.features.maxConnections ?? 10,

399

env: config.environment

400

})

401

};

402

403

const appConfig: AppConfig = {

404

database: {

405

host: "localhost",

406

port: 5432,

407

ssl: true

408

},

409

features: {

410

enableAnalytics: true,

411

maxConnections: 20

412

},

413

environment: 'production'

414

};

415

416

const configFile = ConfigToFileEncoder.encode(appConfig);

417

// result: {

418

// database_url: "postgresql://localhost:5432",

419

// analytics_enabled: true,

420

// max_connections: 20,

421

// env: "production"

422

// }

423

```