or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdconfiguration.mddebugging-service.mdindex.mdstate-types.md

state-types.mddocs/

0

# State Management Types

1

2

Enhanced state structures and type definitions that provide devtools metadata alongside application state, enabling comprehensive debugging capabilities.

3

4

## Capabilities

5

6

### Lifted State Interface

7

8

The primary enhanced state structure containing both application state and devtools metadata.

9

10

```typescript { .api }

11

/**

12

* Enhanced state containing devtools metadata alongside application state

13

*/

14

interface LiftedState {

15

/** Monitor's internal state for custom monitors */

16

monitorState: any;

17

/** Counter for generating unique action IDs */

18

nextActionId: number;

19

/** Map of action IDs to lifted actions */

20

actionsById: LiftedActions;

21

/** Array of action IDs that are staged for execution */

22

stagedActionIds: number[];

23

/** Array of action IDs that have been skipped */

24

skippedActionIds: number[];

25

/** The last committed application state */

26

committedState: any;

27

/** Index of the currently displayed state */

28

currentStateIndex: number;

29

/** Array of computed states with their results */

30

computedStates: ComputedState[];

31

/** Whether state changes are locked */

32

isLocked: boolean;

33

/** Whether action recording is paused */

34

isPaused: boolean;

35

}

36

```

37

38

**Usage Example:**

39

40

```typescript

41

import { Injectable } from "@angular/core";

42

import { StoreDevtools, LiftedState } from "@ngrx/store-devtools";

43

import { map, filter } from "rxjs/operators";

44

45

@Injectable()

46

export class StateAnalysisService {

47

constructor(private devtools: StoreDevtools) {}

48

49

// Monitor state changes

50

monitorStateChanges() {

51

return this.devtools.liftedState.pipe(

52

map((liftedState: LiftedState) => ({

53

totalActions: liftedState.nextActionId,

54

currentIndex: liftedState.currentStateIndex,

55

skippedCount: liftedState.skippedActionIds.length,

56

isLocked: liftedState.isLocked,

57

isPaused: liftedState.isPaused,

58

}))

59

);

60

}

61

62

// Get current application state

63

getCurrentAppState() {

64

return this.devtools.liftedState.pipe(

65

map((liftedState: LiftedState) => {

66

const currentState = liftedState.computedStates[liftedState.currentStateIndex];

67

return currentState ? currentState.state : liftedState.committedState;

68

})

69

);

70

}

71

72

// Check for state errors

73

getStateErrors() {

74

return this.devtools.liftedState.pipe(

75

map((liftedState: LiftedState) =>

76

liftedState.computedStates.filter(state => state.error)

77

),

78

filter(errorStates => errorStates.length > 0)

79

);

80

}

81

}

82

```

83

84

### Computed State Interface

85

86

Represents a single computed state with potential error information.

87

88

```typescript { .api }

89

/**

90

* Single computed state containing the result of applying actions

91

*/

92

interface ComputedState {

93

/** The computed application state */

94

state: any;

95

/** Error that occurred during state computation, if any */

96

error: any;

97

}

98

```

99

100

### Lifted Action Interface

101

102

Wrapper for actions that includes devtools metadata.

103

104

```typescript { .api }

105

/**

106

* Wrapper for actions that includes devtools metadata

107

*/

108

interface LiftedAction {

109

/** Action type string */

110

type: string;

111

/** The original action object */

112

action: Action;

113

}

114

```

115

116

### Lifted Actions Map

117

118

Collection of lifted actions indexed by their IDs.

119

120

```typescript { .api }

121

/**

122

* Map of action IDs to lifted actions

123

*/

124

interface LiftedActions {

125

[id: number]: LiftedAction;

126

}

127

```

128

129

**Usage Example:**

130

131

```typescript

132

import { Injectable } from "@angular/core";

133

import { StoreDevtools, LiftedActions, LiftedAction } from "@ngrx/store-devtools";

134

135

@Injectable()

136

export class ActionAnalysisService {

137

constructor(private devtools: StoreDevtools) {}

138

139

// Get actions by type

140

getActionsByType(actionType: string) {

141

return this.devtools.liftedState.pipe(

142

map(liftedState => liftedState.actionsById),

143

map((actionsById: LiftedActions) =>

144

Object.values(actionsById).filter((liftedAction: LiftedAction) =>

145

liftedAction.action.type === actionType

146

)

147

)

148

);

149

}

150

151

// Get action frequency statistics

152

getActionFrequencyStats() {

153

return this.devtools.liftedState.pipe(

154

map(liftedState => liftedState.actionsById),

155

map((actionsById: LiftedActions) => {

156

const frequency: { [actionType: string]: number } = {};

157

158

Object.values(actionsById).forEach((liftedAction: LiftedAction) => {

159

const type = liftedAction.action.type;

160

frequency[type] = (frequency[type] || 0) + 1;

161

});

162

163

return frequency;

164

})

165

);

166

}

167

168

// Find actions with specific payload properties

169

findActionsWithPayload(propertyName: string, propertyValue: any) {

170

return this.devtools.liftedState.pipe(

171

map(liftedState => liftedState.actionsById),

172

map((actionsById: LiftedActions) =>

173

Object.entries(actionsById)

174

.filter(([id, liftedAction]) => {

175

const payload = (liftedAction.action as any).payload;

176

return payload && payload[propertyName] === propertyValue;

177

})

178

.map(([id, liftedAction]) => ({ id: parseInt(id), action: liftedAction }))

179

)

180

);

181

}

182

}

183

```

184

185

### Core Action Types

186

187

Additional action types that work with the devtools system.

188

189

```typescript { .api }

190

/**

191

* NgRx store initialization action type

192

*/

193

type InitAction = {

194

readonly type: typeof INIT;

195

};

196

197

/**

198

* NgRx store reducer update action type

199

*/

200

type UpdateReducerAction = {

201

readonly type: typeof UPDATE;

202

};

203

204

/**

205

* Union of core NgRx actions

206

*/

207

type CoreActions = InitAction | UpdateReducerAction;

208

209

/**

210

* Union of all devtools and core actions

211

*/

212

type Actions = DevtoolsActions.All | CoreActions;

213

```

214

215

### Recompute Constants

216

217

Constants related to state recomputation.

218

219

```typescript { .api }

220

/** Constant for recompute action type */

221

const RECOMPUTE = '@ngrx/store-devtools/recompute';

222

223

/** Recompute action object */

224

const RECOMPUTE_ACTION = { type: RECOMPUTE };

225

226

/** NgRx store initialization action object */

227

const INIT_ACTION = { type: INIT };

228

```

229

230

**Advanced Usage Example:**

231

232

```typescript

233

import { Injectable } from "@angular/core";

234

import { Store } from "@ngrx/store";

235

import {

236

StoreDevtools,

237

LiftedState,

238

ComputedState,

239

LiftedAction,

240

RECOMPUTE_ACTION

241

} from "@ngrx/store-devtools";

242

import { withLatestFrom, tap, map, distinctUntilChanged, take } from "rxjs/operators";

243

244

@Injectable()

245

export class AdvancedStateService {

246

constructor(

247

private store: Store,

248

private devtools: StoreDevtools

249

) {}

250

251

// Compare states at different points in time

252

compareStates(index1: number, index2: number) {

253

return this.devtools.liftedState.pipe(

254

map((liftedState: LiftedState) => {

255

const state1 = liftedState.computedStates[index1];

256

const state2 = liftedState.computedStates[index2];

257

258

return {

259

state1: state1 ? state1.state : null,

260

state2: state2 ? state2.state : null,

261

error1: state1 ? state1.error : null,

262

error2: state2 ? state2.error : null,

263

hasErrors: (state1?.error || state2?.error) !== null,

264

};

265

})

266

);

267

}

268

269

// Track state size changes

270

trackStateSizeChanges() {

271

return this.devtools.liftedState.pipe(

272

map((liftedState: LiftedState) => {

273

const currentState = liftedState.computedStates[liftedState.currentStateIndex];

274

if (!currentState) return 0;

275

276

return JSON.stringify(currentState.state).length;

277

}),

278

distinctUntilChanged(),

279

tap(size => console.log(`State size changed to: ${size} characters`))

280

);

281

}

282

283

// Export simplified state history

284

exportStateHistory() {

285

return this.devtools.liftedState.pipe(

286

take(1),

287

map((liftedState: LiftedState) => {

288

const history = liftedState.stagedActionIds.map(actionId => {

289

const liftedAction = liftedState.actionsById[actionId];

290

const computedState = liftedState.computedStates.find(

291

(state, index) => liftedState.stagedActionIds[index] === actionId

292

);

293

294

return {

295

actionId,

296

actionType: liftedAction?.action.type,

297

hasError: computedState?.error !== null,

298

timestamp: (liftedAction?.action as any).timestamp || Date.now(),

299

};

300

});

301

302

return {

303

totalActions: liftedState.nextActionId,

304

currentIndex: liftedState.currentStateIndex,

305

isLocked: liftedState.isLocked,

306

isPaused: liftedState.isPaused,

307

history,

308

};

309

})

310

);

311

}

312

313

// Force recompute of all states

314

forceRecompute() {

315

this.devtools.dispatch(RECOMPUTE_ACTION);

316

}

317

318

// Get performance metrics

319

getPerformanceMetrics() {

320

return this.devtools.liftedState.pipe(

321

map((liftedState: LiftedState) => {

322

const totalActions = liftedState.nextActionId;

323

const errorCount = liftedState.computedStates.filter(state => state.error).length;

324

const skippedCount = liftedState.skippedActionIds.length;

325

326

return {

327

totalActions,

328

errorCount,

329

skippedCount,

330

activeActions: totalActions - skippedCount,

331

errorRate: totalActions > 0 ? (errorCount / totalActions) * 100 : 0,

332

memoryUsage: JSON.stringify(liftedState).length,

333

};

334

})

335

);

336

}

337

}

338

```