Skip to content

Instantly share code, notes, and snippets.

@twfarland
Created July 21, 2021 20:03
Show Gist options
  • Save twfarland/03fe3afb8a3dc07a1802cfac89a666f8 to your computer and use it in GitHub Desktop.
Save twfarland/03fe3afb8a3dc07a1802cfac89a666f8 to your computer and use it in GitHub Desktop.
Experiment in doing FRP directly with svelte stores (no external library like RxJS)
import {
derived,
writable,
Readable,
Unsubscriber,
readable,
} from "svelte/store";
export function map<A, B>(
mapper: (value: A) => B,
store: Readable<A>
): Readable<B> {
return derived(store, mapper);
}
export function filter<A>(
predicate: (value: A) => boolean,
store: Readable<A>
): Readable<A> {
return derived(store, (value, set) => {
if (predicate(value)) {
set(value);
}
});
}
export function reduce<A, B>(
reducer: (value: A, accumulated: B) => B,
seed: B,
store: Readable<A>
): Readable<B> {
let acc: B = seed;
return derived(store, (value, set) => {
set(acc);
acc = reducer(value, acc);
});
}
export function dropRepeats<A>(store: Readable<A>): Readable<A> {
let prev: A | undefined = undefined;
return derived(store, (value, set) => {
if (value !== prev) {
prev = value;
set(value);
}
});
}
export function flatMap<A, B>(
lift: (value: A) => Readable<B>,
store: Readable<A>,
initialValue: B
): Readable<B> {
const flat = writable(initialValue);
store.subscribe((value) => {
lift(value).subscribe(flat.set);
});
return flat;
}
export function flatMapLatest<A, B>(
lift: (value: A) => Readable<B>,
store: Readable<A>,
initialValue: B
): Readable<B> {
const flat = writable(initialValue);
let unsubscriber: Unsubscriber | undefined = undefined;
store.subscribe((value) => {
if (unsubscriber) {
unsubscriber();
}
unsubscriber = lift(value).subscribe(flat.set);
});
return flat;
}
export function merge<Union>(
stores: Array<Readable<Union>>,
initialValue: Union
) {
const merged = writable<Union>(initialValue);
for (const store of stores) {
store.subscribe((v) => merged.set(v));
}
return merged;
}
export function sampleOn<A, B>(
store1: Readable<A>,
store2: Readable<B>,
initialValue: A
): Readable<A> {
let value1 = initialValue;
store1.subscribe((value) => {
value1 = value;
});
return derived(store2, (_, set) => {
set(value1);
});
}
export function slidingWindow<A>(
length: number,
store: Readable<A>
): Readable<A[]> {
let frame: A[] = [];
return derived(store, (value) => {
if (frame.length > length - 1) frame.shift();
frame.push(value);
return [...frame];
});
}
export function debounce<A>(
quiet: number,
store: Readable<A>,
initialValue: A
): Readable<A> {
return flatMapLatest(
(value) => {
return fromCallback((callback) => {
setTimeout(() => {
callback(value);
}, quiet);
});
},
store,
initialValue
);
}
export function fromCallback<A>(
callback: (f: (value: A) => void) => void
): Readable<A> {
return readable<A>(undefined, (set) => {
callback((value) => {
set(value);
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment