or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

argument-transformation.mdcache-introspection.mdcache-management.mdcore-memoization.mdequality-comparison.mdindex.mdspecialized-memoization.mdstatistics-profiling.mdutility-methods.md

specialized-memoization.mddocs/

0

# Specialized Memoization

1

2

Specialized memoization methods optimized for specific use cases including promises, React components, and argument serialization.

3

4

## Capabilities

5

6

### Promise Memoization

7

8

Specialized memoization for async functions and promises with automatic resolution caching.

9

10

```typescript { .api }

11

/**

12

* Promise/async function memoization with automatic resolution caching

13

* Sets isPromise: true and updateExpire: true by default

14

* @returns Moizer optimized for promise-based functions

15

*/

16

promise: Moizer<{ isPromise: true }>;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

import moize from "moize";

23

24

// API call memoization

25

const fetchUser = async (userId: string) => {

26

const response = await fetch(`/api/users/${userId}`);

27

if (!response.ok) throw new Error(`Failed to fetch user ${userId}`);

28

return response.json();

29

};

30

31

const memoizedFetchUser = moize.promise(fetchUser);

32

33

// First call - makes HTTP request

34

const user1 = await memoizedFetchUser("123");

35

36

// Second call - returns cached promise result

37

const user2 = await memoizedFetchUser("123");

38

39

// Database query memoization

40

const getUserFromDB = async (id: number) => {

41

const result = await db.query('SELECT * FROM users WHERE id = ?', [id]);

42

return result[0];

43

};

44

45

const memoizedDBQuery = moize.promise.maxAge(30000)(getUserFromDB);

46

47

// Combining with other options

48

const advancedPromiseMemoization = moize.promise

49

.maxSize(50)

50

.maxAge(60000)

51

.profile('api-calls')(fetchUser);

52

```

53

54

### React Component Memoization

55

56

Specialized memoization for React components with props-based caching.

57

58

```typescript { .api }

59

/**

60

* React component memoization based on props comparison

61

* Creates component wrapper that memoizes based on props and context

62

* @returns Moizer optimized for React components

63

*/

64

react: Moizer<{ isReact: true }>;

65

```

66

67

**Usage Examples:**

68

69

```typescript

70

import moize from "moize";

71

import React from "react";

72

73

// Basic component memoization

74

interface UserCardProps {

75

user: {

76

id: number;

77

name: string;

78

email: string;

79

};

80

theme: 'light' | 'dark';

81

}

82

83

const UserCard: React.FC<UserCardProps> = ({ user, theme }) => (

84

<div className={`user-card user-card--${theme}`}>

85

<h3>{user.name}</h3>

86

<p>{user.email}</p>

87

</div>

88

);

89

90

const MemoizedUserCard = moize.react(UserCard);

91

92

// Component with deep props comparison

93

const ComplexComponent: React.FC<{

94

data: { items: any[]; metadata: Record<string, any> };

95

config: { showDetails: boolean; sortBy: string };

96

}> = ({ data, config }) => {

97

// Complex rendering logic

98

return <div>{/* rendered content */}</div>;

99

};

100

101

const MemoizedComplexComponent = moize.react.deep(ComplexComponent);

102

103

// With additional configuration

104

const OptimizedComponent = moize.react

105

.maxSize(10) // Keep 10 different prop combinations

106

.shallow // Use shallow comparison for props

107

(UserCard);

108

109

// Functional component with hooks

110

const CounterComponent: React.FC<{ initialCount: number }> = ({ initialCount }) => {

111

const [count, setCount] = React.useState(initialCount);

112

113

return (

114

<div>

115

<span>Count: {count}</span>

116

<button onClick={() => setCount(c => c + 1)}>Increment</button>

117

</div>

118

);

119

};

120

121

const MemoizedCounter = moize.react(CounterComponent);

122

```

123

124

### useMoize Hook Pattern

125

126

Custom React hook pattern for using moize within functional components with hooks.

127

128

```typescript { .api }

129

/**

130

* Custom hook pattern for memoization within React functional components

131

* Not a built-in export - user-implemented pattern from the documentation

132

*/

133

function useMoize<T extends (...args: any[]) => any>(

134

fn: T,

135

args: Parameters<T>,

136

options?: Options<T>

137

): ReturnType<T>;

138

```

139

140

**Implementation Example:**

141

142

```typescript

143

import { useRef } from 'react';

144

import moize from 'moize';

145

146

export function useMoize(fn, args, options) {

147

const moizedFnRef = useRef(moize(fn, options));

148

149

return moizedFnRef.current(...args);

150

}

151

```

152

153

**Usage Examples:**

154

155

```typescript

156

import React from 'react';

157

import { useMoize } from './moize-hooks';

158

159

function MyComponent({ first, second, object }) {

160

// Standard usage

161

const sum = useMoize((a, b) => a + b, [first, second]);

162

163

// With options

164

const deepSum = useMoize((obj) => obj.a + obj.b, [object], {

165

isDeepEqual: true,

166

});

167

168

return (

169

<div>

170

Sum of {first} and {second} is {sum}. Sum of {object.a} and{' '}

171

{object.b} is {deepSum}.

172

</div>

173

);

174

}

175

176

// Advanced usage with complex computations

177

function DataProcessingComponent({ data, filters, sortBy }) {

178

// Expensive data processing with memoization

179

const processedData = useMoize(

180

(items, filterConfig, sort) => {

181

return items

182

.filter(item => filterConfig.active ? item.status === 'active' : true)

183

.filter(item => filterConfig.category ? item.category === filterConfig.category : true)

184

.sort((a, b) => sort === 'name' ? a.name.localeCompare(b.name) : a.id - b.id);

185

},

186

[data, filters, sortBy],

187

{

188

isDeepEqual: true,

189

maxSize: 10,

190

profileName: 'data-processing'

191

}

192

);

193

194

// Complex calculation with custom equality

195

const aggregatedStats = useMoize(

196

(items) => ({

197

total: items.length,

198

active: items.filter(item => item.status === 'active').length,

199

categories: [...new Set(items.map(item => item.category))].length,

200

avgValue: items.reduce((sum, item) => sum + item.value, 0) / items.length

201

}),

202

[processedData],

203

{

204

maxAge: 30000, // 30 second TTL

205

isShallowEqual: true

206

}

207

);

208

209

return (

210

<div>

211

<h3>Processed Data ({processedData.length} items)</h3>

212

<div>Stats: {aggregatedStats.active} active, {aggregatedStats.categories} categories</div>

213

{/* Render processed data */}

214

</div>

215

);

216

}

217

```

218

219

### Serialization-based Memoization

220

221

Memoization using argument serialization for complex cache key generation.

222

223

```typescript { .api }

224

/**

225

* Serialization-based memoization using default JSON serialization

226

* Converts arguments to strings for cache key comparison

227

* @returns Moizer with serialization enabled

228

*/

229

serialize: Moizer<{ isSerialized: true }>;

230

231

/**

232

* Serialization-based memoization with custom serializer

233

* @param serializer Custom function to serialize cache keys

234

* @returns Moizer with custom serialization

235

*/

236

serializeWith<Serializer extends Serialize>(

237

serializer: Serializer

238

): Moizer<{ isSerialized: true; serializer: Serializer }>;

239

240

type Serialize = (key: Key) => string[];

241

type Key<Arg extends any = any> = Arg[];

242

```

243

244

**Usage Examples:**

245

246

```typescript

247

import moize from "moize";

248

249

// Default JSON serialization

250

const processComplexObject = (obj: {

251

data: any[];

252

options: Record<string, any>;

253

}) => {

254

return obj.data.map(item => ({ ...item, ...obj.options }));

255

};

256

257

const serializedMemoized = moize.serialize(processComplexObject);

258

259

const obj1 = { data: [{ id: 1 }], options: { active: true } };

260

const obj2 = { data: [{ id: 1 }], options: { active: true } }; // Different objects, same content

261

262

console.log(serializedMemoized(obj1)); // Computed

263

console.log(serializedMemoized(obj2)); // Cached (serialization matches)

264

265

// Custom serialization

266

const customSerializer = (key: any[]) => {

267

return key.map(arg => {

268

if (typeof arg === 'object' && arg !== null) {

269

// Sort object keys before stringifying for consistent serialization

270

const sortedObj = Object.keys(arg)

271

.sort()

272

.reduce((result, key) => {

273

result[key] = arg[key];

274

return result;

275

}, {} as any);

276

return JSON.stringify(sortedObj);

277

}

278

return String(arg);

279

});

280

};

281

282

const customSerializedMemoized = moize.serializeWith(customSerializer)(processComplexObject);

283

284

// Serialization with other options

285

const advancedSerialized = moize.serialize

286

.maxSize(20)

287

.maxAge(45000)

288

.profile('serialized-operations')(processComplexObject);

289

290

// Case-insensitive string serialization

291

const caseInsensitiveSerializer = (key: any[]) => {

292

return key.map(arg => {

293

if (typeof arg === 'string') {

294

return arg.toLowerCase();

295

}

296

return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);

297

});

298

};

299

300

const textProcessor = (text: string, options: { trim: boolean }) => {

301

return options.trim ? text.trim().toUpperCase() : text.toUpperCase();

302

};

303

304

const caseInsensitiveMemoized = moize.serializeWith(caseInsensitiveSerializer)(textProcessor);

305

306

console.log(caseInsensitiveMemoized("Hello", { trim: true })); // Computed

307

console.log(caseInsensitiveMemoized("HELLO", { trim: true })); // Cached (case-insensitive)

308

```

309

310

### Combining Specialized Methods

311

312

Specialized methods can be combined with other moize features for comprehensive optimization.

313

314

```typescript

315

import moize from "moize";

316

317

// Promise memoization with size and TTL limits

318

const apiCall = async (endpoint: string, params: Record<string, any>) => {

319

const url = new URL(endpoint);

320

Object.entries(params).forEach(([key, value]) => {

321

url.searchParams.append(key, String(value));

322

});

323

324

const response = await fetch(url.toString());

325

return response.json();

326

};

327

328

const optimizedApiCall = moize.promise

329

.serialize // Handle complex params objects

330

.maxSize(100) // Cache up to 100 different calls

331

.maxAge(300000) // 5 minute TTL

332

.profile('api') // Monitor performance

333

(apiCall);

334

335

// React component with deep comparison and size limit

336

const DataVisualization: React.FC<{

337

data: Array<{ id: string; values: number[] }>;

338

config: {

339

chartType: 'bar' | 'line' | 'pie';

340

colors: string[];

341

showLegend: boolean;

342

};

343

}> = ({ data, config }) => {

344

// Complex chart rendering

345

return <div>{/* chart content */}</div>;

346

};

347

348

const MemoizedVisualization = moize.react

349

.deep // Deep comparison for data and config

350

.maxSize(5) // Keep 5 different data/config combinations

351

(DataVisualization);

352

```

353

354

### Performance Considerations

355

356

Different specialized methods have different performance characteristics:

357

358

- **Promise memoization**: Best for async operations with network calls or heavy computations

359

- **React memoization**: Optimizes component re-rendering, especially with complex props

360

- **Serialization**: Adds overhead but enables complex object comparison without deep equality