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

schema.mddocs/

0

# Schema & Type Classes

1

2

Advanced schema-based type construction and functional programming abstractions for maximum composability.

3

4

## Capabilities

5

6

### Schema Interface

7

8

The core Schema interface for creating reusable, composable type definitions.

9

10

```typescript { .api }

11

/**

12

* Schema interface for creating composable type definitions

13

* @template A - The runtime type

14

*/

15

interface Schema<A> {

16

<S>(S: Schemable<S>): HKT<S, A>;

17

}

18

19

/** Extract type from Schema */

20

type TypeOf<S> = S extends Schema<infer A> ? A : never;

21

```

22

23

### Schema Constructor

24

25

Function for creating memoized schemas.

26

27

```typescript { .api }

28

/**

29

* Create a memoized schema

30

* @param schema - The schema function

31

*/

32

function make<A>(schema: Schema<A>): Schema<A>;

33

34

/**

35

* Interpret a schema with a specific Schemable instance

36

* @param S - The Schemable instance

37

*/

38

function interpreter<S>(S: Schemable<S>): <A>(schema: Schema<A>) => HKT<S, A>;

39

```

40

41

**Usage Example:**

42

43

```typescript

44

import * as S from "io-ts/Schema";

45

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

46

import * as G from "io-ts/Guard";

47

48

// Create a reusable schema

49

const PersonSchema = S.make(S =>

50

S.struct({

51

name: S.string,

52

age: S.number,

53

email: S.string

54

})

55

);

56

57

// Interpret schema as different implementations

58

const PersonDecoder = S.interpreter(D.Schemable)(PersonSchema);

59

const PersonGuard = S.interpreter(G.Schemable)(PersonSchema);

60

61

// Use the generated decoder and guard

62

const result = PersonDecoder.decode({ name: "Alice", age: 30, email: "alice@example.com" });

63

const isValid = PersonGuard.is({ name: "Bob", age: 25, email: "bob@example.com" });

64

```

65

66

### Schemable Type Classes

67

68

Core type classes that define the capability interfaces for different implementations.

69

70

```typescript { .api }

71

/** Literal value types */

72

type Literal = string | number | boolean | null;

73

74

/**

75

* Base Schemable interface for type-level programming

76

* @template S - The HKT parameter

77

*/

78

interface Schemable<S> {

79

readonly URI: S;

80

readonly literal: <A extends [Literal, ...Array<Literal>]>(...values: A) => HKT<S, A[number]>;

81

readonly string: HKT<S, string>;

82

readonly number: HKT<S, number>;

83

readonly boolean: HKT<S, boolean>;

84

readonly nullable: <A>(or: HKT<S, A>) => HKT<S, A | null>;

85

readonly struct: <A>(properties: { [K in keyof A]: HKT<S, A[K]> }) => HKT<S, A>;

86

readonly partial: <A>(properties: { [K in keyof A]: HKT<S, A[K]> }) => HKT<S, Partial<A>>;

87

readonly record: <A>(codomain: HKT<S, A>) => HKT<S, Record<string, A>>;

88

readonly array: <A>(item: HKT<S, A>) => HKT<S, Array<A>>;

89

readonly tuple: <A extends ReadonlyArray<unknown>>(...components: { [K in keyof A]: HKT<S, A[K]> }) => HKT<S, A>;

90

readonly intersect: <B>(right: HKT<S, B>) => <A>(left: HKT<S, A>) => HKT<S, A & B>;

91

readonly lazy: <A>(f: () => HKT<S, A>) => HKT<S, A>;

92

readonly readonly: <A>(inner: HKT<S, A>) => HKT<S, Readonly<A>>;

93

}

94

95

/**

96

* Schemable interface for URIS (Higher-Kinded Types with single parameter)

97

*/

98

interface Schemable1<S extends URIS> {

99

readonly URI: S;

100

readonly literal: <A extends [Literal, ...Array<Literal>]>(...values: A) => Kind<S, A[number]>;

101

readonly string: Kind<S, string>;

102

readonly number: Kind<S, number>;

103

readonly boolean: Kind<S, boolean>;

104

readonly nullable: <A>(or: Kind<S, A>) => Kind<S, A | null>;

105

readonly struct: <A>(properties: { [K in keyof A]: Kind<S, A[K]> }) => Kind<S, A>;

106

readonly partial: <A>(properties: { [K in keyof A]: Kind<S, A[K]> }) => Kind<S, Partial<A>>;

107

readonly record: <A>(codomain: Kind<S, A>) => Kind<S, Record<string, A>>;

108

readonly array: <A>(item: Kind<S, A>) => Kind<S, Array<A>>;

109

readonly tuple: <A extends ReadonlyArray<unknown>>(...components: { [K in keyof A]: Kind<S, A[K]> }) => Kind<S, A>;

110

readonly intersect: <B>(right: Kind<S, B>) => <A>(left: Kind<S, A>) => Kind<S, A & B>;

111

readonly lazy: <A>(f: () => Kind<S, A>) => Kind<S, A>;

112

readonly readonly: <A>(inner: Kind<S, A>) => Kind<S, Readonly<A>>;

113

}

114

115

/**

116

* Schemable interface for URIS2 with error parameter (Higher-Kinded Types with two parameters)

117

*/

118

interface Schemable2C<S extends URIS2, E> {

119

readonly URI: S;

120

readonly _E: E;

121

readonly literal: <A extends [Literal, ...Array<Literal>]>(...values: A) => Kind2<S, E, A[number]>;

122

readonly string: Kind2<S, E, string>;

123

readonly number: Kind2<S, E, number>;

124

readonly boolean: Kind2<S, E, boolean>;

125

readonly nullable: <A>(or: Kind2<S, E, A>) => Kind2<S, E, A | null>;

126

readonly struct: <A>(properties: { [K in keyof A]: Kind2<S, E, A[K]> }) => Kind2<S, E, A>;

127

readonly partial: <A>(properties: { [K in keyof A]: Kind2<S, E, A[K]> }) => Kind2<S, E, Partial<A>>;

128

readonly record: <A>(codomain: Kind2<S, E, A>) => Kind2<S, E, Record<string, A>>;

129

readonly array: <A>(item: Kind2<S, E, A>) => Kind2<S, E, Array<A>>;

130

readonly tuple: <A extends ReadonlyArray<unknown>>(...components: { [K in keyof A]: Kind2<S, E, A[K]> }) => Kind2<S, E, A>;

131

readonly intersect: <B>(right: Kind2<S, E, B>) => <A>(left: Kind2<S, E, A>) => Kind2<S, E, A & B>;

132

readonly lazy: <A>(f: () => Kind2<S, E, A>) => Kind2<S, E, A>;

133

readonly readonly: <A>(inner: Kind2<S, E, A>) => Kind2<S, E, Readonly<A>>;

134

}

135

```

136

137

### Extended Schemable Interfaces

138

139

Additional interfaces for unknown containers, unions, and refinements.

140

141

```typescript { .api }

142

/**

143

* Schemable interface with unknown container support

144

*/

145

interface WithUnknownContainers<S> {

146

readonly UnknownArray: HKT<S, Array<unknown>>;

147

readonly UnknownRecord: HKT<S, Record<string, unknown>>;

148

}

149

150

interface WithUnknownContainers1<S extends URIS> {

151

readonly UnknownArray: Kind<S, Array<unknown>>;

152

readonly UnknownRecord: Kind<S, Record<string, unknown>>;

153

}

154

155

interface WithUnknownContainers2C<S extends URIS2, E> {

156

readonly UnknownArray: Kind2<S, E, Array<unknown>>;

157

readonly UnknownRecord: Kind2<S, E, Record<string, unknown>>;

158

}

159

160

/**

161

* Schemable interface with union support

162

*/

163

interface WithUnion<S> {

164

readonly union: <MS extends [HKT<S, any>, HKT<S, any>, ...Array<HKT<S, any>>]>(...members: MS) => HKT<S, TypeOf<MS[number]>>;

165

}

166

167

interface WithUnion1<S extends URIS> {

168

readonly union: <MS extends [Kind<S, any>, Kind<S, any>, ...Array<Kind<S, any>>]>(...members: MS) => Kind<S, TypeOf<MS[number]>>;

169

}

170

171

interface WithUnion2C<S extends URIS2, E> {

172

readonly union: <MS extends [Kind2<S, E, any>, Kind2<S, E, any>, ...Array<Kind2<S, E, any>>]>(...members: MS) => Kind2<S, E, TypeOf<MS[number]>>;

173

}

174

175

/**

176

* Schemable interface with refinement support

177

*/

178

interface WithRefine<S> {

179

readonly refine: <A, B extends A>(refinement: Refinement<A, B>, id: string) => (from: HKT<S, A>) => HKT<S, B>;

180

}

181

182

interface WithRefine1<S extends URIS> {

183

readonly refine: <A, B extends A>(refinement: Refinement<A, B>, id: string) => (from: Kind<S, A>) => Kind<S, B>;

184

}

185

186

interface WithRefine2C<S extends URIS2, E> {

187

readonly refine: <A, B extends A>(refinement: Refinement<A, B>, id: string) => (from: Kind2<S, E, A>) => Kind2<S, E, B>;

188

}

189

```

190

191

### Utility Functions

192

193

Helper functions for schema operations.

194

195

```typescript { .api }

196

/**

197

* Memoization utility for expensive computations

198

* @param f - Function to memoize

199

*/

200

function memoize<A, B>(f: (a: A) => B): (a: A) => B;

201

202

/**

203

* Internal intersection utility

204

* @param a - First value

205

* @param b - Second value

206

*/

207

function intersect_<A, B>(a: A, b: B): A & B;

208

```

209

210

## Advanced Usage Patterns

211

212

### Multi-Implementation Schema

213

214

```typescript

215

import * as S from "io-ts/Schema";

216

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

217

import * as G from "io-ts/Guard";

218

import * as Eq from "io-ts/Eq";

219

220

// Define a schema once

221

const UserSchema = S.make(S =>

222

S.struct({

223

id: S.number,

224

name: S.string,

225

email: S.string,

226

age: S.number,

227

isActive: S.boolean

228

})

229

);

230

231

// Generate multiple implementations

232

const UserDecoder = S.interpreter(D.Schemable)(UserSchema);

233

const UserGuard = S.interpreter(G.Schemable)(UserSchema);

234

const UserEq = S.interpreter(Eq.Schemable)(UserSchema);

235

236

// Use each implementation for its purpose

237

const userData = { id: 1, name: "Alice", email: "alice@example.com", age: 30, isActive: true };

238

239

// Decode untrusted data

240

const decodeResult = UserDecoder.decode(userData);

241

242

// Type guard for runtime checks

243

if (UserGuard.is(userData)) {

244

console.log("Valid user data");

245

}

246

247

// Compare users for equality

248

const user1 = userData;

249

const user2 = { ...userData, name: "Bob" };

250

const areEqual = UserEq.equals(user1, user2); // false

251

```

252

253

### Complex Nested Schema

254

255

```typescript

256

import * as S from "io-ts/Schema";

257

258

const AddressSchema = S.make(S =>

259

S.struct({

260

street: S.string,

261

city: S.string,

262

country: S.string,

263

postalCode: S.string

264

})

265

);

266

267

const CompanySchema = S.make(S =>

268

S.struct({

269

name: S.string,

270

industry: S.string,

271

employees: S.number,

272

address: S.interpreter(S)(AddressSchema)

273

})

274

);

275

276

const PersonSchema = S.make(S =>

277

S.struct({

278

id: S.number,

279

profile: S.struct({

280

firstName: S.string,

281

lastName: S.string,

282

email: S.string

283

}),

284

addresses: S.array(S.interpreter(S)(AddressSchema)),

285

company: S.nullable(S.interpreter(S)(CompanySchema)),

286

preferences: S.partial({

287

theme: S.union(S.literal('light'), S.literal('dark')),

288

notifications: S.boolean,

289

language: S.string

290

})

291

})

292

);

293

294

// Generate decoder for the complex nested structure

295

const PersonDecoder = S.interpreter(D.Schemable)(PersonSchema);

296

```

297

298

### Recursive Schema

299

300

```typescript

301

import * as S from "io-ts/Schema";

302

303

interface TreeNode {

304

value: number;

305

children: TreeNode[];

306

}

307

308

const TreeSchema: S.Schema<TreeNode> = S.make(S =>

309

S.lazy(() =>

310

S.struct({

311

value: S.number,

312

children: S.array(S.interpreter(S)(TreeSchema))

313

})

314

)

315

);

316

317

const TreeDecoder = S.interpreter(D.Schemable)(TreeSchema);

318

319

const treeData = {

320

value: 1,

321

children: [

322

{ value: 2, children: [] },

323

{ value: 3, children: [{ value: 4, children: [] }] }

324

]

325

};

326

327

const result = TreeDecoder.decode(treeData);

328

```

329

330

### Schema with Refinements

331

332

```typescript

333

import * as S from "io-ts/Schema";

334

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

335

336

const EmailSchema = S.make(S =>

337

S.refine(

338

(s: string): s is string => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s),

339

'Email'

340

)(S.string)

341

);

342

343

const PositiveNumberSchema = S.make(S =>

344

S.refine(

345

(n: number): n is number => n > 0,

346

'PositiveNumber'

347

)(S.number)

348

);

349

350

const ValidatedUserSchema = S.make(S =>

351

S.struct({

352

name: S.refine(

353

(s: string): s is string => s.length > 0,

354

'NonEmptyString'

355

)(S.string),

356

email: S.interpreter(S)(EmailSchema),

357

age: S.interpreter(S)(PositiveNumberSchema)

358

})

359

);

360

361

const ValidatedUserDecoder = S.interpreter(D.Schemable)(ValidatedUserSchema);

362

```