or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composite.mdconstraints.mdcontracts.mdindex.mdliterals.mdprimitives.mdresults.mdtemplates.mdunion-intersect.mdutilities.mdvalidation.md

composite.mddocs/

0

# Composite Types

1

2

Complex data structure validators for arrays, objects, tuples, and records. These types allow validation of structured data with specific element and property types.

3

4

## Capabilities

5

6

### Array

7

8

Validates arrays where all elements conform to a specific element type.

9

10

```typescript { .api }

11

/**

12

* Creates a validator for arrays of a specific element type

13

* @param element - Runtype for validating each array element

14

* @example Array(String).check(["a", "b", "c"]) // ["a", "b", "c"]

15

* @example Array(Number).check([1, 2, "3"]) // throws ValidationError

16

*/

17

function Array<R extends Runtype.Core>(element: R): Array<R>;

18

19

interface Array<R extends Runtype.Core = Runtype.Core> extends Runtype<Static<R>[], Parsed<R>[]> {

20

tag: "array";

21

element: R;

22

asReadonly(): Array.Readonly<R>;

23

}

24

```

25

26

**Usage Examples:**

27

28

```typescript

29

import { Array, String, Number, Object } from "runtypes";

30

31

// Basic arrays

32

const StringArray = Array(String);

33

const NumberArray = Array(Number);

34

35

const names = StringArray.check(["Alice", "Bob", "Charlie"]);

36

const scores = NumberArray.check([95, 87, 92]);

37

38

// Nested arrays

39

const Matrix = Array(Array(Number));

40

const grid = Matrix.check([[1, 2], [3, 4], [5, 6]]);

41

42

// Arrays of objects

43

const UserArray = Array(Object({

44

id: Number,

45

name: String,

46

active: Boolean

47

}));

48

49

const users = UserArray.check([

50

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

51

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

52

]);

53

54

// Readonly arrays

55

const ReadonlyNames = Array(String).asReadonly();

56

type ReadonlyNamesType = Static<typeof ReadonlyNames>; // readonly string[]

57

```

58

59

### Object

60

61

Validates objects with specific property types and structures.

62

63

```typescript { .api }

64

/**

65

* Creates a validator for objects with specified property types

66

* @param fields - Object mapping property names to their runtypes

67

* @example Object({ name: String, age: Number }).check({ name: "Alice", age: 25 })

68

*/

69

function Object<O extends Object.Fields>(fields: O): Object<O>;

70

71

interface Object<O extends Object.Fields = Object.Fields> extends Runtype<ObjectStatic<O>, ObjectParsed<O>> {

72

tag: "object";

73

fields: O;

74

isExact: boolean;

75

76

asPartial(): Object<PartialFields<O>>;

77

asReadonly(): Object.Readonly<O>;

78

pick<K extends keyof O>(...keys: K[]): Object<Pick<O, K>>;

79

omit<K extends keyof O>(...keys: K[]): Object<Omit<O, K>>;

80

extend<P extends Object.Fields>(fields: P): Object<O & P>;

81

exact(): Object<O>;

82

}

83

84

namespace Object {

85

export type Fields = Record<PropertyKey, Runtype.Core | Optional>;

86

}

87

```

88

89

**Usage Examples:**

90

91

```typescript

92

import { Object, String, Number, Boolean, Optional } from "runtypes";

93

94

// Basic object validation

95

const User = Object({

96

id: Number,

97

name: String,

98

email: String,

99

active: Boolean

100

});

101

102

const user = User.check({

103

id: 1,

104

name: "Alice",

105

email: "alice@example.com",

106

active: true

107

});

108

109

// Optional properties

110

const UserWithOptionals = Object({

111

id: Number,

112

name: String,

113

email: String.optional(),

114

age: Number.optional(),

115

bio: String.default("No bio provided")

116

});

117

118

// Object manipulation methods

119

const PartialUser = User.asPartial(); // All properties optional

120

const UserNameOnly = User.pick("name", "email"); // Only name and email

121

const UserWithoutId = User.omit("id"); // All except id

122

123

// Extended objects

124

const AdminUser = User.extend({

125

role: String,

126

permissions: Array(String)

127

});

128

129

// Exact objects (reject extra properties)

130

const StrictUser = User.exact();

131

StrictUser.check({

132

id: 1,

133

name: "Alice",

134

email: "alice@example.com",

135

active: true,

136

extra: "not allowed" // throws ValidationError

137

});

138

```

139

140

### Tuple

141

142

Validates fixed-length arrays with specific types for each position.

143

144

```typescript { .api }

145

/**

146

* Creates a validator for tuples with specific element types at each position

147

* @param components - Runtypes for each tuple element in order

148

* @example Tuple(String, Number).check(["Alice", 25]) // ["Alice", 25]

149

* @example Tuple(String, Number).check(["Alice"]) // throws ValidationError (wrong length)

150

*/

151

function Tuple<T extends readonly Runtype[]>(...components: T): TupleRuntype<T>;

152

153

interface TupleRuntype<T> extends Runtype<TupleType<T>> {

154

tag: "tuple";

155

components: T;

156

asReadonly(): ReadonlyTupleRuntype<T>;

157

}

158

```

159

160

**Usage Examples:**

161

162

```typescript

163

import { Tuple, String, Number, Boolean } from "runtypes";

164

165

// Basic tuples

166

const NameAge = Tuple(String, Number);

167

const person = NameAge.check(["Alice", 25]); // ["Alice", 25]

168

169

// Coordinates

170

const Point2D = Tuple(Number, Number);

171

const Point3D = Tuple(Number, Number, Number);

172

173

const point2d = Point2D.check([10, 20]);

174

const point3d = Point3D.check([10, 20, 30]);

175

176

// Mixed types

177

const UserRecord = Tuple(Number, String, Boolean);

178

const record = UserRecord.check([1, "Alice", true]);

179

180

// Rest elements (using Spread)

181

import { Spread } from "runtypes";

182

183

const NumbersWithLabel = Tuple(String, Spread(Array(Number)));

184

const data = NumbersWithLabel.check(["scores", 95, 87, 92, 88]);

185

186

// Readonly tuples

187

const ReadonlyPoint = Point2D.asReadonly();

188

type ReadonlyPointType = Static<typeof ReadonlyPoint>; // readonly [number, number]

189

```

190

191

### Record

192

193

Validates objects with dynamic keys but uniform value types.

194

195

```typescript { .api }

196

/**

197

* Creates a validator for objects with dynamic keys and uniform value types

198

* @param key - Runtype for validating object keys

199

* @param value - Runtype for validating all object values

200

* @example Record(String, Number).check({ a: 1, b: 2 }) // { a: 1, b: 2 }

201

*/

202

function Record<K extends PropertyKey, V>(

203

key: Runtype<K>,

204

value: Runtype<V>

205

): RecordRuntype<K, V>;

206

207

interface RecordRuntype<K, V> extends Runtype<Record<K, V>> {

208

tag: "record";

209

key: Runtype<K>;

210

value: Runtype<V>;

211

}

212

```

213

214

**Usage Examples:**

215

216

```typescript

217

import { Record, String, Number, Union, Literal } from "runtypes";

218

219

// String keys with number values

220

const StringNumberRecord = Record(String, Number);

221

const scores = StringNumberRecord.check({

222

alice: 95,

223

bob: 87,

224

charlie: 92

225

});

226

227

// Specific string keys

228

const AllowedKeys = Union(Literal("red"), Literal("green"), Literal("blue"));

229

const ColorValues = Record(AllowedKeys, Number);

230

const colors = ColorValues.check({

231

red: 255,

232

green: 128,

233

blue: 64

234

});

235

236

// Number keys (for array-like objects)

237

const NumberStringRecord = Record(Number, String);

238

const arrayLike = NumberStringRecord.check({

239

0: "first",

240

1: "second",

241

2: "third"

242

});

243

244

// Complex value types

245

const UserProfiles = Record(String, Object({

246

name: String,

247

age: Number,

248

active: Boolean

249

}));

250

251

const profiles = UserProfiles.check({

252

"user1": { name: "Alice", age: 25, active: true },

253

"user2": { name: "Bob", age: 30, active: false }

254

});

255

```

256

257

## Advanced Patterns

258

259

### Nested Structures

260

261

```typescript

262

import { Object, Array, Tuple, Record, String, Number } from "runtypes";

263

264

// Deeply nested object

265

const Company = Object({

266

name: String,

267

departments: Array(Object({

268

name: String,

269

employees: Array(Object({

270

id: Number,

271

name: String,

272

position: String,

273

salary: Number

274

})),

275

budget: Number

276

})),

277

metadata: Record(String, String)

278

});

279

280

// Mixed structure with tuples and arrays

281

const DataSet = Object({

282

name: String,

283

points: Array(Tuple(Number, Number)), // Array of [x, y] coordinates

284

labels: Record(Number, String), // Index to label mapping

285

config: Object({

286

title: String,

287

axes: Tuple(String, String) // [x-axis label, y-axis label]

288

})

289

});

290

```

291

292

### Optional and Partial Patterns

293

294

```typescript

295

import { Object, String, Number, Optional } from "runtypes";

296

297

// Explicit optional properties

298

const UserProfile = Object({

299

id: Number,

300

name: String,

301

email: String,

302

phone: String.optional(),

303

avatar: String.optional(),

304

bio: String.default("No bio available")

305

});

306

307

// Convert existing object to partial

308

const PartialProfile = UserProfile.asPartial();

309

// All properties become optional

310

311

// Update patterns

312

const UserUpdate = UserProfile.omit("id").asPartial();

313

// Remove id, make rest optional for updates

314

```

315

316

### Type Extraction

317

318

```typescript

319

import { Object, Array, String, Number, type Static } from "runtypes";

320

321

const ApiResponse = Object({

322

data: Array(Object({

323

id: Number,

324

title: String,

325

tags: Array(String)

326

})),

327

meta: Object({

328

total: Number,

329

page: Number,

330

hasMore: Boolean

331

})

332

});

333

334

// Extract TypeScript types

335

type ApiResponseType = Static<typeof ApiResponse>;

336

// {

337

// data: {

338

// id: number;

339

// title: string;

340

// tags: string[];

341

// }[];

342

// meta: {

343

// total: number;

344

// page: number;

345

// hasMore: boolean;

346

// };

347

// }

348

349

// Use in functions

350

function processApiResponse(response: unknown): ApiResponseType {

351

return ApiResponse.check(response);

352

}

353

```