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

utility-methods.mddocs/

0

# Utility Methods

1

2

Utility functions for working with memoized functions, composition, and type checking in the moize ecosystem.

3

4

## Capabilities

5

6

### Type Checking

7

8

Check if a value is a memoized function created by moize.

9

10

```typescript { .api }

11

/**

12

* Type guard to check if a value is a memoized function

13

* @param value The value to test

14

* @returns True if the value is a memoized function, false otherwise

15

*/

16

isMoized(value: any): value is Moized;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

import moize from "moize";

23

24

const regularFunction = (x: number) => x * 2;

25

const memoizedFunction = moize(regularFunction);

26

27

// Type checking

28

console.log(moize.isMoized(regularFunction)); // false

29

console.log(moize.isMoized(memoizedFunction)); // true

30

console.log(moize.isMoized("not a function")); // false

31

console.log(moize.isMoized(null)); // false

32

33

// Use in conditional logic

34

function processFunction(fn: any) {

35

if (moize.isMoized(fn)) {

36

console.log('Working with memoized function');

37

console.log('Cache size:', Array.from(fn.keys()).length);

38

console.log('Original function name:', fn.originalFunction.name);

39

40

// Access memoized function methods

41

fn.clear();

42

console.log('Cache cleared');

43

} else if (typeof fn === 'function') {

44

console.log('Working with regular function');

45

console.log('Function name:', fn.name);

46

} else {

47

console.log('Not a function');

48

}

49

}

50

51

processFunction(regularFunction); // "Working with regular function"

52

processFunction(memoizedFunction); // "Working with memoized function"

53

54

// Type-safe utility function

55

function getMemoizedFunctionStats(fn: unknown): { calls: number; hits: number } | null {

56

if (moize.isMoized(fn)) {

57

return fn.getStats();

58

}

59

return null;

60

}

61

62

const stats = getMemoizedFunctionStats(memoizedFunction);

63

console.log(stats); // { calls: 0, hits: 0 }

64

```

65

66

### Function Composition

67

68

Compose multiple moizers to create complex memoization strategies.

69

70

```typescript { .api }

71

/**

72

* Compose multiple moizers into a single moizer

73

* @param moizers The moizers or moize instances to compose

74

* @returns A composed moizer that applies all configurations

75

*/

76

compose(...moizers: Array<Moize | Moizer>): Moizer;

77

```

78

79

**Usage Examples:**

80

81

```typescript

82

import moize from "moize";

83

84

// Define individual moization strategies

85

const withCaching = moize.maxSize(50);

86

const withTTL = moize.maxAge(30000); // 30 seconds

87

const withProfiling = moize.profile('composed-functions');

88

const withDeepEquality = moize.deep;

89

90

// Compose strategies

91

const composedMemoizer = moize.compose(

92

withCaching,

93

withTTL,

94

withProfiling,

95

withDeepEquality

96

);

97

98

const expensiveOperation = (data: { items: any[]; config: any }) => {

99

return data.items

100

.filter(item => item.active)

101

.map(item => ({ ...item, processed: true, timestamp: Date.now() }));

102

};

103

104

// Apply composed memoization

105

const memoizedOperation = composedMemoizer(expensiveOperation);

106

107

// The function now has all composed behaviors:

108

// - Max 50 cache entries

109

// - 30 second TTL

110

// - Profiled under 'composed-functions'

111

// - Uses deep equality for comparison

112

113

console.log(memoizedOperation.options);

114

// Contains all merged options from composed moizers

115

116

// Complex composition example

117

const apiMemoizer = moize.compose(

118

moize.promise, // Handle async functions

119

moize.serialize, // Serialize complex arguments

120

moize.maxAge(60000), // 1 minute TTL

121

moize.maxSize(100), // Up to 100 cached responses

122

moize.profile('api-calls') // Profile API performance

123

);

124

125

const fetchUserData = async (userId: string, includePreferences: boolean) => {

126

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

127

return response.json();

128

};

129

130

const memoizedFetchUserData = apiMemoizer(fetchUserData);

131

132

// Database operation composition

133

const dbMemoizer = moize.compose(

134

moize.promise,

135

moize.deep, // Deep comparison for query objects

136

moize.maxAge(120000), // 2 minute TTL

137

moize.transformArgs((key) => { // Normalize query objects

138

return key.map(arg => {

139

if (arg && typeof arg === 'object' && 'query' in arg) {

140

// Sort query keys for consistent caching

141

const sortedQuery = Object.keys(arg.query)

142

.sort()

143

.reduce((result, key) => {

144

result[key] = arg.query[key];

145

return result;

146

}, {} as any);

147

return { ...arg, query: sortedQuery };

148

}

149

return arg;

150

});

151

}),

152

moize.profile('database')

153

);

154

155

const queryDatabase = async (query: { table: string; where: any; limit?: number }) => {

156

// Database query implementation

157

return { results: [], count: 0 };

158

};

159

160

const memoizedDbQuery = dbMemoizer(queryDatabase);

161

```

162

163

### Composition Order and Behavior

164

165

The order of composition matters for certain options, with later moizers taking precedence.

166

167

```typescript

168

import moize from "moize";

169

170

const func = (x: number) => x * x;

171

172

// Order matters for conflicting options

173

const composed1 = moize.compose(

174

moize.maxSize(10), // This will be overridden

175

moize.maxSize(20) // This takes precedence

176

);

177

178

const composed2 = moize.compose(

179

moize.maxSize(20), // This will be overridden

180

moize.maxSize(10) // This takes precedence

181

);

182

183

const memoized1 = composed1(func);

184

const memoized2 = composed2(func);

185

186

console.log(memoized1.options.maxSize); // 20

187

console.log(memoized2.options.maxSize); // 10

188

189

// Non-conflicting options are merged

190

const mergedComposition = moize.compose(

191

moize.maxSize(15),

192

moize.maxAge(5000),

193

moize.deep,

194

moize.profile('merged')

195

);

196

197

const mergedMemoized = mergedComposition(func);

198

console.log(mergedMemoized.options);

199

// {

200

// maxSize: 15,

201

// maxAge: 5000,

202

// isDeepEqual: true,

203

// profileName: 'merged',

204

// // ... other options

205

// }

206

```

207

208

### Practical Composition Patterns

209

210

Common composition patterns for different use cases.

211

212

```typescript

213

import moize from "moize";

214

215

// API call memoization pattern

216

const createApiMemoizer = (cacheDuration: number, cacheSize: number, profileName: string) => {

217

return moize.compose(

218

moize.promise,

219

moize.serialize,

220

moize.maxAge(cacheDuration, {

221

updateExpire: true, // Refresh TTL on cache hits

222

onExpire: (key) => console.log(`API cache expired for:`, key)

223

}),

224

moize.maxSize(cacheSize),

225

moize.profile(profileName)

226

);

227

};

228

229

// Usage

230

const shortTermApiMemoizer = createApiMemoizer(30000, 50, 'short-api'); // 30s

231

const longTermApiMemoizer = createApiMemoizer(300000, 20, 'long-api'); // 5min

232

233

// Computation memoization pattern

234

const createComputationMemoizer = (isHeavyComputation: boolean) => {

235

const baseComposition = [

236

moize.deep, // Usually need deep equality for complex data

237

moize.profile('computations')

238

];

239

240

if (isHeavyComputation) {

241

return moize.compose(

242

...baseComposition,

243

moize.infinite, // No size limit for expensive computations

244

moize.transformArgs((key) => {

245

// Normalize computation arguments

246

return key.map(arg => {

247

if (Array.isArray(arg)) {

248

return [...arg].sort(); // Sort arrays for consistent caching

249

}

250

return arg;

251

});

252

})

253

);

254

} else {

255

return moize.compose(

256

...baseComposition,

257

moize.maxSize(100),

258

moize.maxAge(60000) // 1 minute for lighter computations

259

);

260

}

261

};

262

263

// React component memoization pattern

264

const createReactMemoizer = (useDeepComparison: boolean = false) => {

265

const composition = [moize.react, moize.maxSize(20)];

266

267

if (useDeepComparison) {

268

composition.push(moize.deep);

269

} else {

270

composition.push(moize.shallow);

271

}

272

273

return moize.compose(...composition);

274

};

275

276

// Development vs Production memoization

277

const createEnvironmentMemoizer = (isDevelopment: boolean) => {

278

const baseComposition = [

279

moize.maxSize(50),

280

moize.maxAge(60000)

281

];

282

283

if (isDevelopment) {

284

// More verbose profiling and smaller cache in development

285

return moize.compose(

286

...baseComposition,

287

moize.profile('dev-functions'),

288

moize.collectStats(true)

289

);

290

} else {

291

// Optimized for production

292

return moize.compose(

293

...baseComposition,

294

moize.serialize // Better cache key consistency in production

295

);

296

}

297

};

298

```