or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

array-operations.mdextension-system.mdfunction-operations.mdindex.mdmap-set-operations.mdobject-operations.md
tile.json

index.mddocs/

0

# Immutability Helper

1

2

Immutability Helper provides a MongoDB-inspired syntax for creating modified copies of JavaScript data structures without mutating the original data. It serves as a drop-in replacement for React's deprecated `react-addons-update`, offering powerful immutable update operations with shallow copying for performance.

3

4

## Package Information

5

6

- **Package Name**: immutability-helper

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install immutability-helper`

10

11

## Core Imports

12

13

```typescript

14

import update from "immutability-helper";

15

import { Context, extend, isEquals, invariant } from "immutability-helper";

16

```

17

18

For CommonJS:

19

20

```javascript

21

const update = require("immutability-helper");

22

const { Context, extend, isEquals, invariant } = require("immutability-helper");

23

```

24

25

## Basic Usage

26

27

```typescript

28

import update from "immutability-helper";

29

30

// Update arrays

31

const initialArray = [1, 2, 3];

32

const newArray = update(initialArray, { $push: [4] }); // [1, 2, 3, 4]

33

34

// Update objects

35

const obj = { a: 5, b: 3 };

36

const newObj = update(obj, { b: { $set: 6 } }); // { a: 5, b: 6 }

37

38

// Nested updates

39

const collection = [1, 2, { a: [12, 17, 15] }];

40

const newCollection = update(collection, {

41

2: { a: { $splice: [[1, 1, 13, 14]] } }

42

}); // [1, 2, { a: [12, 13, 14, 15] }]

43

44

// Function-based updates

45

const updated = update(obj, { b: { $apply: x => x * 2 } });

46

```

47

48

## Architecture

49

50

Immutability Helper is built around several core concepts:

51

52

- **Update Function**: The main `update(object, spec)` function that applies specifications to data

53

- **Command System**: MongoDB-inspired `$`-prefixed commands for different operation types

54

- **Context System**: `Context` class for isolated environments with custom commands

55

- **Type Safety**: Full TypeScript support with generic type preservation

56

- **Shallow Copying**: Efficient copying strategy that only copies changed branches

57

- **Reference Equality**: Preserves object references when no changes occur for performance

58

59

## Capabilities

60

61

### Array Operations

62

63

Core operations for modifying arrays including push, unshift, and splice operations.

64

65

```typescript { .api }

66

// Push items to end of array

67

{ $push: ReadonlyArray<T> }

68

69

// Add items to beginning of array

70

{ $unshift: ReadonlyArray<T> }

71

72

// Perform splice operations

73

{ $splice: ReadonlyArray<[number, number?] | [number, number, ...T[]]> }

74

```

75

76

[Array Operations](./array-operations.md)

77

78

### Object Operations

79

80

Operations for modifying object properties including set, merge, toggle, and unset.

81

82

```typescript { .api }

83

// Replace target entirely

84

{ $set: T }

85

86

// Shallow merge properties

87

{ $merge: Partial<T> }

88

89

// Toggle boolean fields

90

{ $toggle: ReadonlyArray<keyof T> }

91

92

// Remove properties

93

{ $unset: ReadonlyArray<keyof T> }

94

```

95

96

[Object Operations](./object-operations.md)

97

98

### Map and Set Operations

99

100

Specialized operations for ES6 Map and Set data structures.

101

102

```typescript { .api }

103

// Add entries to Map or Set

104

{ $add: ReadonlyArray<[K, V]> | ReadonlyArray<T> }

105

106

// Remove entries from Map or Set

107

{ $remove: ReadonlyArray<K> }

108

```

109

110

[Map and Set Operations](./map-set-operations.md)

111

112

### Function Operations

113

114

Function-based operations for complex transformations and custom logic.

115

116

```typescript { .api }

117

// Apply function to current value

118

{ $apply: (v: T) => T }

119

120

// Shorthand: pass function directly

121

(v: T) => T

122

```

123

124

[Function Operations](./function-operations.md)

125

126

### Context and Extension System

127

128

Advanced features for creating isolated contexts and adding custom commands.

129

130

```typescript { .api }

131

class Context {

132

constructor();

133

extend<T>(directive: string, fn: (param: any, old: T) => T): void;

134

update<T, C extends CustomCommands<object> = never>(object: T, $spec: Spec<T, C>): T;

135

get isEquals(): (x: any, y: any) => boolean;

136

set isEquals(value: (x: any, y: any) => boolean);

137

}

138

139

function extend<T>(directive: string, fn: (param: any, old: T) => T): void;

140

```

141

142

[Extension System](./extension-system.md)

143

144

## Limitations

145

146

**Important:** The `update` function only works for _data properties_, not for _accessor properties_ defined with `Object.defineProperty`. It does not see accessor properties and may create shadowing data properties which could break application logic depending on setter side effects. Therefore `update` should only be used on plain data objects that contain only _data properties_ as descendants.

147

148

## Core Types

149

150

```typescript { .api }

151

// Main update function type

152

function update<T, C extends CustomCommands<object> = never>(

153

object: T,

154

$spec: Spec<T, C>

155

): T;

156

157

// Specification type for updates

158

type Spec<T, C extends CustomCommands<object> = never> =

159

| (T extends (Array<infer U> | ReadonlyArray<infer U>) ? ArraySpec<U, C> :

160

T extends (Map<infer K, infer V> | ReadonlyMap<infer K, infer V>) ? MapSpec<K, V, C> :

161

T extends (Set<infer X> | ReadonlySet<infer X>) ? SetSpec<X> :

162

T extends object ? ObjectSpec<T, C> :

163

never)

164

| { $set: T }

165

| { $apply: (v: T) => T }

166

| ((v: T) => T)

167

| (C extends CustomCommands<infer O> ? O : never);

168

169

// Custom commands type brand

170

type CustomCommands<T> = T & { __noInferenceCustomCommandsBrand: any };

171

172

// Specialized spec types

173

type ArraySpec<T, C extends CustomCommands<object>> =

174

| { $push: ReadonlyArray<T> }

175

| { $unshift: ReadonlyArray<T> }

176

| { $splice: ReadonlyArray<[number, number?] | [number, number, ...T[]]> }

177

| { [index: string]: Spec<T, C> };

178

179

type MapSpec<K, V, C extends CustomCommands<object>> =

180

| { $add: ReadonlyArray<[K, V]> }

181

| { $remove: ReadonlyArray<K> }

182

| { [key: string]: Spec<V, C> };

183

184

type SetSpec<T> =

185

| { $add: ReadonlyArray<T> }

186

| { $remove: ReadonlyArray<T> };

187

188

type ObjectSpec<T, C extends CustomCommands<object>> =

189

| { $toggle: ReadonlyArray<keyof T> }

190

| { $unset: ReadonlyArray<keyof T> }

191

| { $merge: Partial<T> }

192

| { [K in keyof T]?: Spec<T[K], C> };

193

194

// Utility functions

195

/**

196

* Throws an error if condition is false

197

* @param condition - Boolean condition to check

198

* @param message - Function that returns error message

199

*/

200

function invariant(condition: boolean, message: () => string): void;

201

202

/**

203

* Default equality function used for change detection

204

* Can be overridden via Context.isEquals

205

*/

206

const isEquals: (x: any, y: any) => boolean;

207

```