or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

additional-namespaces.mdadvanced-types.mdbasic-types.mdcompilation.mdindex.mdjavascript-types.mdtransforms.mdvalue-operations.md

transforms.mddocs/

0

# Transforms

1

2

Bidirectional value encoding and decoding with full type safety for data serialization and processing. Transforms allow you to define how data should be converted between different representations while maintaining TypeScript type safety.

3

4

## Capabilities

5

6

### Transform Creation

7

8

#### Transform Function

9

10

Creates a transform type with encode/decode logic.

11

12

```typescript { .api }

13

/**

14

* Creates a transform type with encode/decode logic

15

* @param schema - Base schema to transform

16

* @returns TransformDecodeBuilder for chaining decode operation

17

*/

18

function Transform<T extends TSchema>(schema: T): TransformDecodeBuilder<T>;

19

20

interface TransformDecodeBuilder<T extends TSchema> {

21

/** Define decode transformation (from schema type to runtime type) */

22

Decode<U>(decode: (value: Static<T>) => U): TransformEncodeBuilder<T, U>;

23

}

24

25

interface TransformEncodeBuilder<T extends TSchema, U> {

26

/** Define encode transformation (from runtime type back to schema type) */

27

Encode<V>(encode: (value: U) => V): TTransform<T, U>;

28

}

29

```

30

31

**Usage Examples:**

32

33

```typescript

34

import { Type, Value } from "@sinclair/typebox";

35

36

// Transform string to Date

37

const DateTransform = Type.Transform(Type.String({ format: 'date-time' }))

38

.Decode(value => new Date(value)) // string -> Date

39

.Encode(value => value.toISOString()); // Date -> string

40

41

// Transform string to number

42

const NumberTransform = Type.Transform(Type.String())

43

.Decode(value => parseFloat(value)) // string -> number

44

.Encode(value => value.toString()); // number -> string

45

46

// Transform with validation and normalization

47

const EmailTransform = Type.Transform(Type.String())

48

.Decode(value => value.toLowerCase().trim()) // string -> normalized string

49

.Encode(value => value); // identity encode

50

```

51

52

### Complex Transforms

53

54

#### Object Property Transforms

55

56

Transform individual properties within objects.

57

58

```typescript

59

// Transform an object with mixed types

60

const UserTransform = Type.Transform(Type.Object({

61

name: Type.String(),

62

birthDate: Type.String({ format: 'date' }),

63

settings: Type.String() // JSON string

64

}))

65

.Decode(value => ({

66

name: value.name,

67

birthDate: new Date(value.birthDate),

68

settings: JSON.parse(value.settings)

69

}))

70

.Encode(value => ({

71

name: value.name,

72

birthDate: value.birthDate.toISOString().split('T')[0],

73

settings: JSON.stringify(value.settings)

74

}));

75

76

// Usage

77

const rawData = {

78

name: "Alice",

79

birthDate: "1990-05-15",

80

settings: '{"theme":"dark","lang":"en"}'

81

};

82

83

const decoded = Value.Decode(UserTransform, rawData);

84

// Result: {

85

// name: "Alice",

86

// birthDate: Date object,

87

// settings: { theme: "dark", lang: "en" }

88

// }

89

90

const encoded = Value.Encode(UserTransform, decoded);

91

// Result: Back to original string-based format

92

```

93

94

#### Array Transforms

95

96

Transform arrays with element-level transformations.

97

98

```typescript

99

// Transform array of date strings to Date objects

100

const DateArrayTransform = Type.Transform(Type.Array(Type.String()))

101

.Decode(value => value.map(str => new Date(str)))

102

.Encode(value => value.map(date => date.toISOString()));

103

104

// Transform CSV-like data

105

const CsvRowTransform = Type.Transform(Type.String())

106

.Decode(value => value.split(',').map(s => s.trim()))

107

.Encode(value => value.join(', '));

108

```

109

110

#### Nested Transforms

111

112

Compose multiple transforms for complex data structures.

113

114

```typescript

115

// Individual transforms

116

const TimestampTransform = Type.Transform(Type.Number())

117

.Decode(value => new Date(value * 1000))

118

.Encode(value => Math.floor(value.getTime() / 1000));

119

120

const JsonTransform = Type.Transform(Type.String())

121

.Decode(value => JSON.parse(value))

122

.Encode(value => JSON.stringify(value));

123

124

// Composed transform

125

const EventTransform = Type.Transform(Type.Object({

126

id: Type.String(),

127

timestamp: Type.Number(),

128

data: Type.String(),

129

tags: Type.Array(Type.String())

130

}))

131

.Decode(value => ({

132

id: value.id,

133

timestamp: new Date(value.timestamp * 1000),

134

data: JSON.parse(value.data),

135

tags: value.tags

136

}))

137

.Encode(value => ({

138

id: value.id,

139

timestamp: Math.floor(value.timestamp.getTime() / 1000),

140

data: JSON.stringify(value.data),

141

tags: value.tags

142

}));

143

```

144

145

### Transform Operations

146

147

#### Decode Operation

148

149

Converts from schema representation to runtime representation.

150

151

```typescript { .api }

152

/**

153

* Decodes transformed values to runtime form

154

* @param schema - Transform schema

155

* @param value - Value in schema representation

156

* @returns Value in runtime representation

157

*/

158

function Decode<T extends TSchema>(schema: T, value: unknown): Static<T>;

159

```

160

161

**Usage Examples:**

162

163

```typescript

164

const StringToNumber = Type.Transform(Type.String())

165

.Decode(value => parseInt(value, 10))

166

.Encode(value => value.toString());

167

168

// Decode string to number

169

const decoded = Value.Decode(StringToNumber, "123");

170

// Result: 123 (number)

171

172

// Works with complex objects

173

const ComplexTransform = Type.Transform(Type.Object({

174

count: Type.String(),

175

active: Type.String()

176

}))

177

.Decode(value => ({

178

count: parseInt(value.count, 10),

179

active: value.active === 'true'

180

}))

181

.Encode(value => ({

182

count: value.count.toString(),

183

active: value.active.toString()

184

}));

185

186

const decodedObject = Value.Decode(ComplexTransform, {

187

count: "42",

188

active: "true"

189

});

190

// Result: { count: 42, active: true }

191

```

192

193

#### Encode Operation

194

195

Converts from runtime representation back to schema representation.

196

197

```typescript { .api }

198

/**

199

* Encodes values using schema transforms

200

* @param schema - Transform schema

201

* @param value - Value in runtime representation

202

* @returns Value in schema representation

203

*/

204

function Encode<T extends TSchema>(schema: T, value: Static<T>): unknown;

205

```

206

207

**Usage Examples:**

208

209

```typescript

210

const DateTransform = Type.Transform(Type.String())

211

.Decode(value => new Date(value))

212

.Encode(value => value.toISOString());

213

214

const now = new Date();

215

const encoded = Value.Encode(DateTransform, now);

216

// Result: "2024-01-15T10:30:00.000Z" (string)

217

218

// Encoding preserves the schema format

219

const roundTrip = Value.Decode(DateTransform, encoded);

220

// Result: Date object equal to original

221

```

222

223

### Validation with Transforms

224

225

Transforms integrate seamlessly with TypeBox validation.

226

227

```typescript

228

const ValidatedTransform = Type.Transform(Type.Object({

229

age: Type.String({ pattern: '^\\d+$' }), // Must be numeric string

230

email: Type.String({ format: 'email' })

231

}))

232

.Decode(value => ({

233

age: parseInt(value.age, 10),

234

email: value.email.toLowerCase()

235

}))

236

.Encode(value => ({

237

age: value.age.toString(),

238

email: value.email

239

}));

240

241

// Validation happens on the schema representation

242

const isValid = Value.Check(ValidatedTransform, {

243

age: "25", // Valid: numeric string

244

email: "USER@EXAMPLE.COM"

245

});

246

247

if (isValid) {

248

const decoded = Value.Decode(ValidatedTransform, {

249

age: "25",

250

email: "USER@EXAMPLE.COM"

251

});

252

// Result: { age: 25, email: "user@example.com" }

253

}

254

```

255

256

### Transform Error Handling

257

258

Handle errors gracefully in transform operations.

259

260

```typescript

261

const SafeJsonTransform = Type.Transform(Type.String())

262

.Decode(value => {

263

try {

264

return JSON.parse(value);

265

} catch (error) {

266

return null; // or throw a custom error

267

}

268

})

269

.Encode(value => {

270

if (value === null) return '{}';

271

return JSON.stringify(value);

272

});

273

274

// Error handling in transforms

275

const SafeNumberTransform = Type.Transform(Type.String())

276

.Decode(value => {

277

const num = parseFloat(value);

278

if (isNaN(num)) {

279

throw new Error(`Invalid number: ${value}`);

280

}

281

return num;

282

})

283

.Encode(value => value.toString());

284

285

try {

286

const result = Value.Decode(SafeNumberTransform, "not-a-number");

287

} catch (error) {

288

console.error("Transform failed:", error.message);

289

}

290

```

291

292

### Advanced Transform Patterns

293

294

#### Conditional Transforms

295

296

Apply different transformations based on value characteristics.

297

298

```typescript

299

const ConditionalTransform = Type.Transform(Type.String())

300

.Decode(value => {

301

// Parse as number if numeric, otherwise keep as string

302

const num = parseFloat(value);

303

return isNaN(num) ? value : num;

304

})

305

.Encode(value => {

306

return typeof value === 'number' ? value.toString() : value;

307

});

308

```

309

310

#### Transform Composition

311

312

Chain multiple transforms for complex processing pipelines.

313

314

```typescript

315

// Base transforms

316

const TrimTransform = Type.Transform(Type.String())

317

.Decode(value => value.trim())

318

.Encode(value => value);

319

320

const UppercaseTransform = Type.Transform(Type.String())

321

.Decode(value => value.toUpperCase())

322

.Encode(value => value.toLowerCase());

323

324

// Composed processing (conceptual - requires custom implementation)

325

function processString(input: string): string {

326

const trimmed = Value.Decode(TrimTransform, input);

327

const uppercased = Value.Decode(UppercaseTransform, trimmed);

328

return uppercased;

329

}

330

```

331

332

#### Database Integration

333

334

Transform between database representations and application models.

335

336

```typescript

337

// Database row to application model

338

const UserRecordTransform = Type.Transform(Type.Object({

339

id: Type.Number(),

340

name: Type.String(),

341

created_at: Type.String(),

342

settings_json: Type.String(),

343

is_active: Type.Number() // SQLite boolean as number

344

}))

345

.Decode(value => ({

346

id: value.id,

347

name: value.name,

348

createdAt: new Date(value.created_at),

349

settings: JSON.parse(value.settings_json),

350

isActive: value.is_active === 1

351

}))

352

.Encode(value => ({

353

id: value.id,

354

name: value.name,

355

created_at: value.createdAt.toISOString(),

356

settings_json: JSON.stringify(value.settings),

357

is_active: value.isActive ? 1 : 0

358

}));

359

```

360

361

## Transform Limitations

362

363

- **Compilation**: Transforms cannot be compiled with TypeCompiler

364

- **Performance**: Runtime overhead compared to direct validation

365

- **Complexity**: Complex transforms can be hard to debug

366

- **Reversibility**: Encode/decode operations should be reversible when possible

367

368

**Best Practices:**

369

370

```typescript

371

// Good: Simple, reversible transform

372

const GoodTransform = Type.Transform(Type.String())

373

.Decode(value => parseInt(value, 10))

374

.Encode(value => value.toString());

375

376

// Avoid: Complex, non-reversible transforms

377

const AvoidTransform = Type.Transform(Type.String())

378

.Decode(value => {

379

// Complex processing that loses information

380

return value.split(',').filter(x => x.length > 0).length;

381

})

382

.Encode(value => value.toString()); // Can't recreate original

383

```

384

385

## Type Interfaces

386

387

```typescript { .api }

388

interface TTransform<T extends TSchema, U> extends TSchema {

389

[TransformKind]: 'Transform';

390

type: T['type'];

391

decode: (value: Static<T>) => U;

392

encode: (value: U) => Static<T>;

393

}

394

395

interface TransformDecodeBuilder<T extends TSchema> {

396

Decode<U>(decode: (value: Static<T>) => U): TransformEncodeBuilder<T, U>;

397

}

398

399

interface TransformEncodeBuilder<T extends TSchema, U> {

400

Encode<V>(encode: (value: U) => V): TTransform<T, U>;

401

}

402

403

// Transform decode/encode function types

404

type TransformFunction<T, U> = (value: T) => U;

405

type DecodeTransformFunction<T extends TSchema, U> = TransformFunction<Static<T>, U>;

406

type EncodeTransformFunction<T, U extends TSchema> = TransformFunction<T, Static<U>>;

407

```