From 52eda23a53061a951fee06050733556a7ad42773 Mon Sep 17 00:00:00 2001 From: Sander Hahn Date: Wed, 15 May 2019 07:34:06 +0200 Subject: [PATCH] advanced type for derived --- src/store.ts | 32 ++++++++++++++++++------------- test/{store/index.js => store.ts} | 28 ++++++++++++++++++++++----- tsconfig.json | 3 +-- 3 files changed, 43 insertions(+), 20 deletions(-) rename test/{store/index.js => store.ts} (88%) diff --git a/src/store.ts b/src/store.ts index e27059a4d7..462f155c2a 100644 --- a/src/store.ts +++ b/src/store.ts @@ -10,24 +10,24 @@ type Invalidater = (value?: T) => void; type StartStopNotifier = (set: Subscriber) => Unsubscriber | void; -export interface ReadableStore { +export interface Readable { subscribe(run: Subscriber, invalidate?: Invalidater): Unsubscriber; } -export interface WritableStore extends ReadableStore { +export interface Writable extends Readable { set(value: T): void; update(updater: Updater): void; } type SubscribeInvalidateTuple = [Subscriber, Invalidater]; -export function readable(value: T, start: StartStopNotifier): ReadableStore { +export function readable(value: T, start: StartStopNotifier): Readable { return { subscribe: writable(value, start).subscribe, }; } -export function writable(value: T, start: StartStopNotifier = noop): WritableStore { +export function writable(value: T, start: StartStopNotifier = noop): Writable { let stop: Unsubscriber; const subscribers: Array> = []; @@ -68,21 +68,27 @@ export function writable(value: T, start: StartStopNotifier = noop): Writa return { set, update, subscribe }; } -export function derived( - stores: ReadableStore | Array>, - fn: (values: T | T[], set?: Subscriber) => T | Unsubscriber | void, - initial_value: T): ReadableStore { +type Stores = Readable | [Readable, ...Array>]; + +type StoresValues = T extends Readable ? U : + { [K in keyof T]: T[K] extends Readable ? U : never }; + +export function derived( + stores: S, + fn: (values: StoresValues, set?: Subscriber) => T | Unsubscriber | void, + initial_value?: T, +): Readable { const single = !Array.isArray(stores); - const stores_array: Array> = single - ? [stores as ReadableStore] - : stores as Array>; + const stores_array: Array> = single + ? [stores as Readable] + : stores as Array>; const auto = fn.length < 2; return readable(initial_value, (set) => { let inited = false; - const values: T[] = []; + const values: StoresValues = [] as StoresValues; let pending = 0; let cleanup = noop; @@ -123,7 +129,7 @@ export function derived( }); } -export function get(store: ReadableStore): T { +export function get(store: Readable): T { let value: T | undefined; store.subscribe((_: T) => value = _)(); return value as T; diff --git a/test/store/index.js b/test/store.ts similarity index 88% rename from test/store/index.js rename to test/store.ts index 5f9176cffb..9b3d5d1788 100644 --- a/test/store/index.js +++ b/test/store.ts @@ -1,5 +1,5 @@ import * as assert from 'assert'; -import { readable, writable, derived, get } from '../../store.js'; +import { readable, writable, derived, get } from '../store'; describe('store', () => { describe('writable', () => { @@ -30,10 +30,10 @@ describe('store', () => { return () => called -= 1; }); - const unsubscribe1 = store.subscribe(() => {}); + const unsubscribe1 = store.subscribe(() => { }); assert.equal(called, 1); - const unsubscribe2 = store.subscribe(() => {}); + const unsubscribe2 = store.subscribe(() => { }); assert.equal(called, 1); unsubscribe1(); @@ -73,7 +73,7 @@ describe('store', () => { set(0); return () => { - tick = () => {}; + tick = () => { }; running = false; }; }); @@ -242,11 +242,29 @@ describe('store', () => { 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', () => { it('gets the current value of a store', () => { - const store = readable(42, () => {}); + const store = readable(42, () => { }); assert.equal(get(store), 42); }); }); diff --git a/tsconfig.json b/tsconfig.json index 5da2d13a01..fdb7367e05 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,8 +7,7 @@ "allowJs": true, "lib": ["es5", "es6", "dom"], "importHelpers": true, - "moduleResolution": "node", - "strict": true + "moduleResolution": "node" }, "include": [ "src"