UNPKG

nanostores

Version:

A tiny (265 bytes) state manager for React/Preact/Vue/Svelte with many atomic tree-shakable stores

150 lines (132 loc) 3.86 kB
import type { AllKeys, ReadableAtom, ReadonlyIfObject, WritableAtom } from '../atom/index.js' type KeyofBase = keyof any type Get<T, K extends KeyofBase> = Extract<T, { [K1 in K]: any }>[K] export type HasIndexSignature<T> = string extends keyof T ? true : false export type ValueWithUndefinedForIndexSignatures< Value, Key extends keyof Value > = HasIndexSignature<Value> extends true ? undefined | Value[Key] : Value[Key] export type WritableStore<Value = any> = | (Value extends object ? MapStore<Value> : never) | WritableAtom<Value> export type Store<Value = any> = ReadableAtom<Value> | WritableStore<Value> export type AnyStore<Value = any> = { get(): Value readonly value: undefined | Value } export type StoreValue<SomeStore> = SomeStore extends { get(): infer Value } ? Value : any export type BaseMapStore<Value = any> = { setKey: (key: any, value: any) => any } & WritableAtom<Value> export type MapStoreKeys<SomeStore> = SomeStore extends { setKey: (key: infer K, ...args: any[]) => any } ? K : AllKeys<StoreValue<SomeStore>> export interface MapStore<Value extends object = any> extends WritableAtom<Value> { /** * Subscribe to store changes. * * In contrast with {@link Store#subscribe} it do not call listener * immediately. * * @param listener Callback with store value and old value. * @param changedKey Key that was changed. Will present only if `setKey` * has been used to change a store. * @returns Function to remove listener. */ listen( listener: ( value: ReadonlyIfObject<Value>, oldValue: ReadonlyIfObject<Value>, changedKey: AllKeys<Value> ) => void ): () => void /** * Low-level method to notify listeners about changes in the store. * * Can cause unexpected behaviour when combined with frontend frameworks * that perform equality checks for values, such as React. */ notify(oldValue?: ReadonlyIfObject<Value>, changedKey?: AllKeys<Value>): void /** * Change store value. * * ```js * $settings.set({ theme: 'dark' }) * ``` * * Operation is atomic, subscribers will be notified once with the new value. * `changedKey` will be undefined * * @param newValue New store value. */ set(newValue: Value): void /** * Change key in store value. * * ```js * $settings.setKey('theme', 'dark') * ``` * * To delete key set `undefined`. * * ```js * $settings.setKey('theme', undefined) * ``` * * @param key The key name. * @param value New value. */ setKey<Key extends AllKeys<Value>>( key: Key, value: Get<Value, Key> | ValueWithUndefinedForIndexSignatures<Value, Key> ): void /** * Subscribe to store changes and call listener immediately. * * ``` * import { $router } from '../store' * * $router.subscribe(page => { * console.log(page) * }) * ``` * * @param listener Callback with store value and old value. * @param changedKey Key that was changed. Will present only * if `setKey` has been used to change a store. * @returns Function to remove listener. */ subscribe( listener: ( value: ReadonlyIfObject<Value>, oldValue: ReadonlyIfObject<Value> | undefined, changedKey: AllKeys<Value> | undefined ) => void ): () => void } export interface PreinitializedMapStore<Value extends object = any> extends MapStore<Value> { readonly value: Value } /** * Create map store. Map store is a store with key-value object * as a store value. * * @param init Initialize store and return store destructor. * @returns The store object with methods to subscribe. */ export function map<Value extends object, StoreExt extends object = object>( value?: Value ): PreinitializedMapStore<Value> & StoreExt