Skip to content

Commit d92092f

Browse files
committed
feat(utils): createKeyedSignal key/value overload
1 parent ca8bfae commit d92092f

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

packages/utils/src/createKeyedSignal.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,57 @@ describe("createKeyedSignal", () => {
4242
subscription2.unsubscribe()
4343
})
4444

45+
it("receives a key selector and returns a tuple with an observable-getter and its corresponding event-emitter", () => {
46+
const [getFooBar$, onFooBar] = createKeyedSignal(
47+
(signal: { key: string; foo: number; bar: string }) => signal.key,
48+
)
49+
50+
let receivedValue1
51+
let nHits1 = 0
52+
const subscription1 = getFooBar$("key").subscribe((val) => {
53+
receivedValue1 = val
54+
nHits1++
55+
})
56+
57+
expect(receivedValue1).toBe(undefined)
58+
onFooBar({ key: "key", foo: 0, bar: "1" })
59+
expect(receivedValue1).toEqual({ foo: 0, bar: "1", key: "key" })
60+
expect(nHits1).toBe(1)
61+
62+
let receivedValue2
63+
let nHits2 = 0
64+
const subscription2 = getFooBar$("key").subscribe((val) => {
65+
receivedValue2 = val
66+
nHits2++
67+
})
68+
69+
expect(receivedValue2).toBe(undefined)
70+
71+
onFooBar({ key: "key", foo: 1, bar: "2" })
72+
expect(receivedValue1).toEqual({ foo: 1, bar: "2", key: "key" })
73+
expect(nHits1).toBe(2)
74+
expect(receivedValue2).toEqual({ foo: 1, bar: "2", key: "key" })
75+
expect(nHits2).toBe(1)
76+
77+
onFooBar({ key: "key2", foo: 1, bar: "2" })
78+
expect(nHits1).toBe(2)
79+
expect(nHits2).toBe(1)
80+
81+
subscription1.unsubscribe()
82+
subscription2.unsubscribe()
83+
})
84+
85+
it("returns a tupe with a typed observable and its corresponding event-emitter for the key-value overload", () => {
86+
const [foo$, onFoo] = createKeyedSignal<string, number>()
87+
let receivedValue
88+
foo$("foo").subscribe((val) => {
89+
receivedValue = val
90+
})
91+
expect(receivedValue).toBe(undefined)
92+
onFoo("foo", 5)
93+
expect(receivedValue).toEqual(5)
94+
})
95+
4596
it('returns a tuple with a typed observable and its corresponding event-emitter when no "event creator" is provided', () => {
4697
const [foo$, onFoo] = createKeyedSignal<string>()
4798
let receivedValue

packages/utils/src/createKeyedSignal.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { GroupedObservable, identity, Observable, Observer } from "rxjs"
1+
import { GroupedObservable, Observable, Observer } from "rxjs"
22

33
/**
44
* Creates a "keyed" signal. It's sugar for splitting the Observer and the Observable of a keyed signal.
@@ -20,7 +20,20 @@ export function createKeyedSignal<T>(): [
2020
* 1. The getter function that returns the GroupedObservable<K, T>
2121
* 2. The emitter function.
2222
*/
23-
export function createKeyedSignal<T, K, A extends any[]>(
23+
export function createKeyedSignal<K, T>(): [
24+
(key: K) => GroupedObservable<K, T>,
25+
(key: K, value: T) => void,
26+
]
27+
28+
/**
29+
* Creates a "keyed" signal. It's sugar for splitting the Observer and the Observable of a keyed signal.
30+
*
31+
* @param keySelector a function that extracts the key from the emitted value
32+
* @returns [1, 2]
33+
* 1. The getter function that returns the GroupedObservable<K, T>
34+
* 2. The emitter function.
35+
*/
36+
export function createKeyedSignal<K, T>(
2437
keySelector: (signal: T) => K,
2538
): [(key: K) => GroupedObservable<K, T>, (signal: T) => void]
2639

@@ -33,14 +46,14 @@ export function createKeyedSignal<T, K, A extends any[]>(
3346
* 1. The getter function that returns the GroupedObservable<K, T>
3447
* 2. The emitter function (...args: any[]) => T.
3548
*/
36-
export function createKeyedSignal<T, K, A extends any[]>(
49+
export function createKeyedSignal<K, T, A extends any[]>(
3750
keySelector: (signal: T) => K,
3851
mapper: (...args: A) => T,
3952
): [(key: K) => GroupedObservable<K, T>, (...args: A) => void]
4053

41-
export function createKeyedSignal<T, K, A extends any[]>(
42-
keySelector: (signal: T) => K = identity as any,
43-
mapper: (...args: A) => T = identity as any,
54+
export function createKeyedSignal<K, T, A extends any[]>(
55+
keySelector?: (signal: T) => K,
56+
mapper?: (...args: A) => T,
4457
): [(key: K) => GroupedObservable<K, T>, (...args: A) => void] {
4558
const observersMap = new Map<K, Set<Observer<T>>>()
4659

@@ -63,8 +76,13 @@ export function createKeyedSignal<T, K, A extends any[]>(
6376
return res
6477
},
6578
(...args: A) => {
66-
const payload = mapper(...args)
67-
observersMap.get(keySelector(payload))?.forEach((o) => {
79+
const payload = mapper
80+
? mapper(...args)
81+
: args.length === 2
82+
? args[1]
83+
: args[0]
84+
const key = keySelector ? keySelector(payload) : args[0]
85+
observersMap.get(key)?.forEach((o) => {
6886
o.next(payload)
6987
})
7088
},

0 commit comments

Comments
 (0)