advanced type for derived

pull/2733/head
Sander Hahn 6 years ago
parent b6b7c621d0
commit 52eda23a53

@ -10,24 +10,24 @@ type Invalidater<T> = (value?: T) => void;
type StartStopNotifier<T> = (set: Subscriber<T>) => Unsubscriber | void; type StartStopNotifier<T> = (set: Subscriber<T>) => Unsubscriber | void;
export interface ReadableStore<T> { export interface Readable<T> {
subscribe(run: Subscriber<T>, invalidate?: Invalidater<T>): Unsubscriber; subscribe(run: Subscriber<T>, invalidate?: Invalidater<T>): Unsubscriber;
} }
export interface WritableStore<T> extends ReadableStore<T> { export interface Writable<T> extends Readable<T> {
set(value: T): void; set(value: T): void;
update(updater: Updater<T>): void; update(updater: Updater<T>): void;
} }
type SubscribeInvalidateTuple<T> = [Subscriber<T>, Invalidater<T>]; type SubscribeInvalidateTuple<T> = [Subscriber<T>, Invalidater<T>];
export function readable<T>(value: T, start: StartStopNotifier<T>): ReadableStore<T> { export function readable<T>(value: T, start: StartStopNotifier<T>): Readable<T> {
return { return {
subscribe: writable(value, start).subscribe, subscribe: writable(value, start).subscribe,
}; };
} }
export function writable<T>(value: T, start: StartStopNotifier<T> = noop): WritableStore<T> { export function writable<T>(value: T, start: StartStopNotifier<T> = noop): Writable<T> {
let stop: Unsubscriber; let stop: Unsubscriber;
const subscribers: Array<SubscribeInvalidateTuple<T>> = []; const subscribers: Array<SubscribeInvalidateTuple<T>> = [];
@ -68,21 +68,27 @@ export function writable<T>(value: T, start: StartStopNotifier<T> = noop): Writa
return { set, update, subscribe }; return { set, update, subscribe };
} }
export function derived<T>( type Stores = Readable<any> | [Readable<any>, ...Array<Readable<any>>];
stores: ReadableStore<T> | Array<ReadableStore<T>>,
fn: (values: T | T[], set?: Subscriber<T>) => T | Unsubscriber | void, type StoresValues<T> = T extends Readable<infer U> ? U :
initial_value: T): ReadableStore<T> { { [K in keyof T]: T[K] extends Readable<infer U> ? U : never };
export function derived<T, S extends Stores>(
stores: S,
fn: (values: StoresValues<S>, set?: Subscriber<T>) => T | Unsubscriber | void,
initial_value?: T,
): Readable<T> {
const single = !Array.isArray(stores); const single = !Array.isArray(stores);
const stores_array: Array<ReadableStore<T>> = single const stores_array: Array<Readable<any>> = single
? [stores as ReadableStore<T>] ? [stores as Readable<any>]
: stores as Array<ReadableStore<T>>; : stores as Array<Readable<any>>;
const auto = fn.length < 2; const auto = fn.length < 2;
return readable(initial_value, (set) => { return readable(initial_value, (set) => {
let inited = false; let inited = false;
const values: T[] = []; const values: StoresValues<S> = [] as StoresValues<S>;
let pending = 0; let pending = 0;
let cleanup = noop; let cleanup = noop;
@ -123,7 +129,7 @@ export function derived<T>(
}); });
} }
export function get<T>(store: ReadableStore<T>): T { export function get<T>(store: Readable<T>): T {
let value: T | undefined; let value: T | undefined;
store.subscribe((_: T) => value = _)(); store.subscribe((_: T) => value = _)();
return value as T; return value as T;

@ -1,5 +1,5 @@
import * as assert from 'assert'; import * as assert from 'assert';
import { readable, writable, derived, get } from '../../store.js'; import { readable, writable, derived, get } from '../store';
describe('store', () => { describe('store', () => {
describe('writable', () => { describe('writable', () => {
@ -30,10 +30,10 @@ describe('store', () => {
return () => called -= 1; return () => called -= 1;
}); });
const unsubscribe1 = store.subscribe(() => {}); const unsubscribe1 = store.subscribe(() => { });
assert.equal(called, 1); assert.equal(called, 1);
const unsubscribe2 = store.subscribe(() => {}); const unsubscribe2 = store.subscribe(() => { });
assert.equal(called, 1); assert.equal(called, 1);
unsubscribe1(); unsubscribe1();
@ -73,7 +73,7 @@ describe('store', () => {
set(0); set(0);
return () => { return () => {
tick = () => {}; tick = () => { };
running = false; running = false;
}; };
}); });
@ -242,11 +242,29 @@ describe('store', () => {
assert.deepEqual(cleaned_up, [2, 3, 4]); assert.deepEqual(cleaned_up, [2, 3, 4]);
}); });
it('allows derived with different types', () => {
const a = writable('one');
const b = writable(1);
const c = derived([a, b], ([a, b]) => `${a} ${b}`);
const values: string[] = [];
const unsubscribe = c.subscribe(value => {
values.push(value);
});
a.set('two');
b.set(2);
assert.deepEqual(values, 'two 2');
unsubscribe();
});
}); });
describe('get', () => { describe('get', () => {
it('gets the current value of a store', () => { it('gets the current value of a store', () => {
const store = readable(42, () => {}); const store = readable(42, () => { });
assert.equal(get(store), 42); assert.equal(get(store), 42);
}); });
}); });

@ -7,8 +7,7 @@
"allowJs": true, "allowJs": true,
"lib": ["es5", "es6", "dom"], "lib": ["es5", "es6", "dom"],
"importHelpers": true, "importHelpers": true,
"moduleResolution": "node", "moduleResolution": "node"
"strict": true
}, },
"include": [ "include": [
"src" "src"

Loading…
Cancel
Save