0
# Function Operations
1
2
Function-based operations for complex transformations and custom logic. These operations allow you to apply custom functions to transform data based on current values.
3
4
## Capabilities
5
6
### Apply Operation
7
8
Applies a function to the current value and replaces it with the function's return value.
9
10
```typescript { .api }
11
/**
12
* Apply a function to the current value
13
* @param fn - Function that receives the current value and returns new value
14
* @returns Result of applying the function to the current value
15
*/
16
{ $apply: (v: T) => T }
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import update from "immutability-helper";
23
24
// Transform numeric value
25
const obj = { count: 5 };
26
const doubled = update(obj, { count: { $apply: x => x * 2 } });
27
// Result: { count: 10 }
28
29
// Transform string value
30
const user = { name: 'alice' };
31
const capitalized = update(user, {
32
name: { $apply: name => name.charAt(0).toUpperCase() + name.slice(1) }
33
});
34
// Result: { name: 'Alice' }
35
36
// Transform array
37
const data = { numbers: [1, 2, 3, 4, 5] };
38
const evensOnly = update(data, {
39
numbers: { $apply: arr => arr.filter(n => n % 2 === 0) }
40
});
41
// Result: { numbers: [2, 4] }
42
43
// Complex object transformation
44
const product = {
45
name: 'laptop',
46
price: 999,
47
specs: { ram: '8GB', storage: '256GB' }
48
};
49
const updated = update(product, {
50
specs: {
51
$apply: specs => ({
52
...specs,
53
ram: '16GB',
54
gpu: 'Integrated'
55
})
56
}
57
});
58
// Result: specs now has ram: '16GB' and new gpu property
59
```
60
61
### Shorthand Function Syntax
62
63
Instead of using `{ $apply: function }`, you can pass a function directly as the specification.
64
65
```typescript { .api }
66
/**
67
* Shorthand syntax for applying a function
68
* @param fn - Function that receives the current value and returns new value
69
* @returns Result of applying the function to the current value
70
*/
71
(v: T) => T
72
```
73
74
**Usage Examples:**
75
76
```typescript
77
import update from "immutability-helper";
78
79
// Shorthand syntax (equivalent to $apply)
80
const obj = { value: 10 };
81
82
// These are equivalent:
83
const result1 = update(obj, { value: { $apply: x => x + 5 } });
84
const result2 = update(obj, { value: x => x + 5 });
85
// Both result in: { value: 15 }
86
87
// Multiple shorthand functions
88
const data = { a: 1, b: 2, c: 3 };
89
const transformed = update(data, {
90
a: x => x * 2,
91
b: x => x + 10,
92
c: x => x.toString()
93
});
94
// Result: { a: 2, b: 12, c: '3' }
95
96
// Nested shorthand
97
const nested = {
98
user: { age: 25, scores: [80, 85, 90] },
99
meta: { count: 3 }
100
};
101
const result = update(nested, {
102
user: {
103
age: age => age + 1,
104
scores: scores => [...scores, 95]
105
},
106
meta: {
107
count: count => count + 1
108
}
109
});
110
// Result: user.age = 26, scores has 95 added, meta.count = 4
111
```
112
113
## Advanced Function Operations
114
115
```typescript
116
import update from "immutability-helper";
117
118
// Conditional updates
119
const user = { name: 'Alice', role: 'user', loginCount: 5 };
120
const conditionalUpdate = update(user, {
121
role: currentRole => currentRole === 'user' && user.loginCount > 3 ? 'trusted' : currentRole,
122
loginCount: count => count + 1
123
});
124
125
// Async function handling (Note: $apply itself is synchronous)
126
const processData = (data: string[]) => {
127
return update(data, {
128
$apply: items => items.map(item => item.toUpperCase()).sort()
129
});
130
};
131
132
// Using external context
133
const multiplier = 3;
134
const numbers = { values: [1, 2, 3, 4] };
135
const scaled = update(numbers, {
136
values: { $apply: arr => arr.map(n => n * multiplier) }
137
});
138
139
// Combining with other operations
140
const complex = {
141
items: [{ id: 1, active: false }, { id: 2, active: true }],
142
count: 2
143
};
144
const processed = update(complex, {
145
items: {
146
$apply: items => items.map(item => ({ ...item, active: !item.active }))
147
},
148
count: count => count * 2
149
});
150
```
151
152
## Error Handling
153
154
Function operations validate their inputs:
155
156
- `$apply` requires the spec value to be a function
157
- Functions should return a value (undefined results are allowed but may cause issues)
158
- Functions are called synchronously and should not throw errors
159
160
```typescript
161
// This will throw an error:
162
update({ value: 1 }, { value: { $apply: 'not a function' } });
163
// Error: update(): expected spec of $apply to be a function
164
165
// Functions should handle edge cases:
166
const safeUpdate = update(obj, {
167
value: {
168
$apply: (current) => {
169
if (typeof current !== 'number') return 0;
170
return current * 2;
171
}
172
}
173
});
174
```
175
176
## Performance Notes
177
178
- Functions are called once per update operation
179
- The function receives the current value as its argument
180
- Return values replace the current value entirely
181
- Reference equality is preserved if the function returns the same reference
182
- Functions should be pure (no side effects) for predictable behavior
183
- Avoid expensive computations in frequently called update functions
184
185
## Best Practices
186
187
```typescript
188
// Good: Pure function
189
const increment = (x: number) => x + 1;
190
update(obj, { count: { $apply: increment } });
191
192
// Good: Simple transformation
193
update(user, { name: name => name.trim().toLowerCase() });
194
195
// Avoid: Side effects
196
update(obj, {
197
value: {
198
$apply: x => {
199
console.log(x); // Side effect - avoid this
200
return x * 2;
201
}
202
}
203
});
204
205
// Good: Handle edge cases
206
update(data, {
207
items: {
208
$apply: items => Array.isArray(items) ? items.filter(Boolean) : []
209
}
210
});
211
```