8000 update / updateIn · immutable-js/immutable-js@3b627ef · GitHub
[go: up one dir, main page]

Skip to content

Commit 3b627ef

Browse files
committed
update / updateIn
1 parent 81b788a commit 3b627ef

File tree

6 files changed

+239
-26
lines changed

6 files changed

+239
-26
lines changed

__tests__/updateIn.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,14 @@ describe('updateIn', () => {
110110
// code that works perfectly
111111
expect(
112112
updateIn({ 10: { 20: 'a' } }, customArray, (v) =>
113+
// @ts-expect-error -- `updateIn` keypath type should be `OrderedCollection<K> | ArrayLike<K>;
113114
typeof v === 'string' ? v.toUpperCase() : v
114115
)
115116
).toEqual({ 10: { 20: 'A' } });
116117

117118
expect(() =>
118119
updateIn({ 10: 'a' }, customArray, (v) =>
120+
// @ts-expect-error -- `updateIn` keypath type should be `OrderedCollection<K> | ArrayLike<K>;
119121
typeof v === 'string' ? v.toUpperCase() : v
120122
)
121123
).toThrow('Cannot update within non-data-structure value in path [10]: a');

src/functional/get.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ export function get<V, NSV>(
4949
key: string,
5050
notSetValue: NSV
5151
): V | NSV;
52+
export function get<K extends PropertyKey, V, NSV>(
53+
collection: Collection<K, V> | Array<V> | { [key: string]: V },
54+
key: K,
55+
notSetValue?: NSV
56+
): V | NSV;
5257
export function get<K extends PropertyKey, V, NSV>(
5358
collection: Collection<K, V> | Array<V> | { [key: string]: V },
5459
key: K,

src/functional/remove.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ export function remove<
3838
C extends { [key: PropertyKey]: unknown },
3939
K extends keyof C,
4040
>(collection: C, key: K): C;
41+
export function remove<
42+
K extends PropertyKey,
43+
C extends
44+
| Collection<K, unknown>
45+
| Array<unknown>
46+
| { [key: PropertyKey]: unknown },
47+
>(collection: C, key: K): C;
4148
export function remove<K extends PropertyKey>(
4249
collection:
4350
| Collection<K, unknown>

src/functional/update.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/functional/update.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import type { Collection, Record } from '../../type-definitions/immutable';
2+
import { updateIn, type PossibleCollection } from './updateIn';
3+
4+
type UpdaterFunction<V> = (value: V | undefined) => V | undefined;
5+
type UpdaterFunctionWithNSV<V, NSV> = (value: V | NSV) => V;
6+
7+
/**
8+
* Returns a copy of the collection with the value at key set to the result of
9+
* providing the existing value to the updating function.
10+
*
11+
* A functional alternative to `collection.update(key, fn)` which will also
12+< F438 div class="diff-text-inner"> * work with plain Objects and Arrays as an alternative for
13+
* `collectionCopy[key] = fn(collection[key])`.
14+
*
15+
* <!-- runkit:activate -->
16+
* ```js
17+
* import { update } from 'immutable';
18+
*
19+
* const originalArray = [ 'dog', 'frog', 'cat' ]
20+
* update(originalArray, 1, val => val.toUpperCase()) // [ 'dog', 'FROG', 'cat' ]
21+
* console.log(originalArray) // [ 'dog', 'frog', 'cat' ]
22+
* const originalObject = { x: 123, y: 456 }
23+
* update(originalObject, 'x', val => val * 6) // { x: 738, y: 456 }
24+
* console.log(originalObject) // { x: 123, y: 456 }
25+
* ```
26+
*/
27+
export function update<K, V, C extends Collection<K, V>>(
28+
collection: C,
29+
key: K,
30+
updater: (value: V | undefined) => V | undefined
31+
): C;
32+
export function update<K, V, C extends Collection<K, V>, NSV>(
33+
collection: C,
34+
key: K,
35+
notSetValue: NSV,
36+
updater: (value: V | NSV) => V
37+
): C;
38+
export function update<
39+
TProps extends object,
40+
C extends Record<TProps>,
41+
K extends keyof TProps,
42+
>(record: C, key: K, updater: (value: TProps[K]) => TProps[K]): C;
43+
export function update<
44+
TProps extends object,
45+
C extends Record<TProps>,
46+
K extends keyof TProps,
47+
NSV,
48+
>(
49+
record: C,
50+
key: K,
51+
notSetValue: NSV,
52+
updater: (value: TProps[K] | NSV) => TProps[K]
53+
): C;
54+
export function update<V, C extends Array<V>>(
55+
collection: C,
56+
key: number,
57+
updater: UpdaterFunction<V>
58+
): C;
59+
export function update<V, C extends Array<V>, NSV>(
60+
collection: C,
61+
key: number,
62+
notSetValue: NSV,
63+
updater: (value: V | NSV) => V
64+
): C;
65+
export function update<C, K extends keyof C>(
66+
object: C,
67+
key: K,
68+
updater: (value: C[K]) => C[K]
69+
): C;
70+
export function update<C, K extends keyof C, NSV>(
71+
object: C,
72+
key: K,
73+
notSetValue: NSV,
74+
updater: (value: C[K] | NSV) => C[K]
75+
): C;
76+
export function update<V, C extends { [key: string]: V }, K extends keyof C>(
77+
collection: C,
78+
key: K,
79+
updater: (value: V) => V
80+
): { [key: string]: V };
81+
export function update<
82+
V,
83+
C extends { [key: string]: V },
84+
K extends keyof C,
85+
NSV,
86+
>(
87+
collection: C,
88+
key: K,
89+
notSetValue: NSV,
90+
updater: (value: V | NSV) => V
91+
): { [key: string]: V };
92+
93+
export function update<
94+
K,
95+
V,
96+
TProps extends object,
97+
C extends PossibleCollection<K, V, TProps>,
98+
NSV,
99+
>(
100+
collection: C,
101+
key: K,
102+
notSetValue: NSV | UpdaterFunction<V>,
103+
updater?: UpdaterFunctionWithNSV<V, NSV>
104+
) {
105+
return updateIn(
106+
// @ts-expect-error Index signature for type string is missing in type V[]
107+
collection,
108+
[key],
109+
notSetValue,
110+
updater
111+
);
112+
}

src/functional/updateIn.ts

Lines changed: 113 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import { emptyMap } from '../Map';
77
import { get } from './get';
88
import { remove } from './remove';
99
import { set } from './set';
10-
import type { KeyPath, update } from '../../type-definitions/immutable';
11-
12-
type UpdaterFunction = (value: unknown) => unknown;
13-
14-
type UpdateTypeParameters = Parameters<typeof update>;
10+
import type {
11+
Collection,
12+
KeyPath,
13+
Record,
14+
RetrievePath,
15+
} from '../../type-definitions/immutable';
1516

1617
/**
1718
* Returns a copy of the collection with the value at key path set to the
@@ -29,30 +30,115 @@ type UpdateTypeParameters = Parameters<typeof update>;
2930
* console.log(original) // { x: { y: { z: 123 }}}
3031
* ```
3132
*/
32-
export function updateIn<C extends UpdateTypeParameters[0]>(
33+
34+
export type PossibleCollection<K, F438 V, TProps extends object> =
35+
| Collection<K, V>
36+
| Record<TProps>
37+
| Array<V>;
38+
39+
type UpdaterFunction<K extends PropertyKey, C> = (
40+
value: RetrievePath<C, Array<K>> | undefined
41+
) => unknown | undefined;
42+
type UpdaterFunctionWithNSV<K extends PropertyKey, C, NSV> = (
43+
value: RetrievePath<C, Array<K>> | NSV
44+
) => unknown;
45+
46+
export function updateIn<K extends PropertyKey, V, C extends Collection<K, V>>(
3347
collection: C,
34-
keyPath: KeyPath<UpdateTypeParameters[1]>,
35-
updater: UpdateTypeParameters[2]
48+
keyPath: KeyPath<K>,
49+
updater: UpdaterFunction<K, C>
3650
): C;
37-
export function updateIn<C extends UpdateTypeParameters[0]>(
51+
export function updateIn<
52+
K extends PropertyKey,
53+
V,
54+
C extends Collection<K, V>,
55+
NSV,
56+
>(
3857
collection: C,
39-
keyPath: KeyPath<UpdateTypeParameters[1]>,
40-
notSetValue: UpdateTypeParameters[2],
41-
updater: UpdateTypeParameters[3]
58+
keyPath: KeyPath<K>,
59+
notSetValue: NSV,
60+
updater: UpdaterFunctionWithNSV<K, C, NSV>
61+
): C;
62+
export function updateIn<
63+
TProps extends object,
64+
C extends Record<TProps>,
65+
K extends keyof TProps,
66+
>(record: C, keyPath: KeyPath<K>, updater: UpdaterFunction<K, C>): C;
67+
export function updateIn<
68+
TProps extends object,
69+
C extends Record<TProps>,
70+
K extends keyof TProps,
71+
NSV,
72+
>(
73+
record: C,
74+
keyPath: KeyPath<K>,
75+
notSetValue: NSV,
76+
updater: UpdaterFunctionWithNSV<K, C, NSV>
4277
): C;
43-
export function updateIn<C extends UpdateTypeParameters[0]>(
78+
export function updateIn<K extends PropertyKey, V, C extends Array<V>>(
79+
collection: C,
80+
keyPath: KeyPath<string | number>,
81+
updater: UpdaterFunction<K, C>
82+
): Array<V>;
83+
export function updateIn<K extends PropertyKey, V, C extends Array<V>, NSV>(
84+
collection: C,
85+
keyPath: KeyPath<K>,
86+
notSetValue: NSV,
87+
updater: UpdaterFunctionWithNSV<K, C, NSV>
88+
): Array<V>;
89+
export function updateIn<K extends PropertyKey, C>(
90+
object: C,
91+
keyPath: KeyPath<K>,
92+
updater: UpdaterFunction<K, C>
93+
): C;
94+
export function updateIn<K extends PropertyKey, C, NSV>(
95+
object: C,
96+
keyPath: KeyPath<K>,
97+
notSetValue: NSV,
98+
updater: UpdaterFunctionWithNSV<K, C, NSV>
99+
): C;
100+
export function updateIn<
101+
K extends PropertyKey,
102+
V,
103+
C extends { [key: PropertyKey]: V },
104+
>(
105+
collection: C,
106+
keyPath: KeyPath<K>,
107+
updater: UpdaterFunction<K, C>
108+
): { [key: PropertyKey]: V };
109+
export function updateIn<
110+
K extends PropertyKey,
111+
V,
112+
C extends { [key: PropertyKey]: V },
113+
NSV,
114+
>(
115+
collection: C,
116+
keyPath: KeyPath<K>,
117+
notSetValue: NSV,
118+
updater: UpdaterFunction<K, C>
119+
): { [key: PropertyKey]: V };
120+
121+
export function updateIn<
122+
K extends PropertyKey,
123+
V,
124+
TProps extends object,
125+
C extends PossibleCollection<K, V, TProps>,
126+
NSV,
127+
>(
44128
collection: C,
45-
keyPath: KeyPath<UpdateTypeParameters[1]>,
46-
notSetValue: UpdateTypeParameters[2],
47-
updater?: UpdateTypeParameters[3]
129+
keyPath: KeyPath<K>,
130+
notSetValue: NSV | UpdaterFunction<K, C> | undefined,
131+
updater?: UpdaterFunctionWithNSV<K, C, NSV>
48132
): C {
49133
if (!updater) {
50134
// handle the fact that `notSetValue` is optional here, in that case `updater` is the updater function
51-
updater = notSetValue as UpdaterFunction;
135+
// @ts-expect-error updater is a function here
136+
updater = notSetValue as UpdaterFunction<K, C>;
52137
notSetValue = undefined;
53138
}
54139
const updatedValue = updateInDeeply(
55140
isImmutable(collection),
141+
// @ts-expect-error type issues with Record and mixed types
56142
collection,
57143
coerceKeyPath(keyPath),
58144
0,
@@ -63,17 +149,23 @@ export function updateIn<C extends UpdateTypeParameters[0]>(
63149
return updatedValue === NOT_SET ? notSetValue : updatedValue;
64150
}
65151

66-
function updateInDeeply<C extends UpdateTypeParameters[0]>(
152+
function updateInDeeply<
153+
K extends PropertyKey,
154+
TProps extends object,
155+
C extends PossibleCollection<unknown, unknown, TProps>,
156+
NSV,
157+
>(
67158
inImmutable: boolean,
68159
existing: C,
69-
keyPath: ArrayLike<UpdateTypeParameters[1]>,
160+
keyPath: Array<K>,
70161
i: number,
71-
notSetValue: UpdateTypeParameters[2],
72-
updater: UpdateTypeParameters[3]
162+
notSetValue: NSV | undefined,
163+
updater: UpdaterFunctionWithNSV<K, C, NSV> | UpdaterFunction<K, C>
73164
): C {
74165
const wasNotSet = existing === NOT_SET;
75166
if (i === keyPath.length) {
76167
const existingValue = wasNotSet ? notSetValue : existing;
168+
// @ts-expect-error mixed type with optional value
77169
const newValue = updater(existingValue);
78170
// @ts-expect-error mixed type
79171
return newValue === existingValue ? existing : newValue;

0 commit comments

Comments
 (0)
0