Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(types): add readonly store and refine useStore typing #1675

Conversation

FaberVitale
Copy link
Contributor

@FaberVitale FaberVitale commented Mar 4, 2023

Related Issues or Discussions

#1589

Fixes #

Allows the creation of read only zustand stores compatible with useStore.

Use case

I'm developing a library and I wanted to expose a read only zustand store.
I've created a function called asReadOnly to create a zustand store without destroy and setState.

Unfortunately I couldn't make it work with useStore so I had to come up with a workaround (useSelector).
I'd like to remove useSelector from asReadOnly output and use useStore without having type issues.

asReadOnly

import { useStore } from 'zustand'
import type { StoreApi } from 'zustand'

type Tail<Arr extends any[]> = Arr extends readonly [unknown, ...infer Rest] ? Rest : never

export function asReadOnly<State>({ getState, subscribe }: StoreApi<State>) {
  return {
    getState,
    subscribe,
    useSelector: ((...args: Tail<Parameters<typeof useStore>>) => useStore(store, ...args))
}

asReadOnly usage

import { asReadOnly } from '../store'
import { createStore, StoreApi } from 'zustand'

describe('asReadOnly', () => {
  it('creates a readonly version of input store', () => {
    const writableStore = createStore(() => ({ a: 2, b: 3, c: 4, d: 5 }))
    const readonlyStore = asReadOnly(writableStore)

    expect(readonlyStore).not.toHaveProperty('setState')
    expect(writableStore.getState()).toBe(readonlyStore.getState())

    writableStore.setState({ a: 1 })
    expect(writableStore.getState().a).toBe(1)
    expect(readonlyStore.getState().a).toBe(1)
  })
})

Summary

  1. Adds ReadOnlyStoreApi a subset of StoreApi that can be used to type read only versions of zustand stores.
  2. Refines useStore typings.
  3. Adds ReadOnlyStoreApi to checkTypes(...).

Check List

  • yarn run prettier for formatting code and docs

@codesandbox-ci
Copy link

codesandbox-ci bot commented Mar 4, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 73fdeed:

Sandbox Source
React Configuration
React Typescript Configuration
React Browserify Configuration
React Snowpack Configuration
React Parcel Configuration
@pavlobu/zustand demo Configuration

@dai-shi
Copy link
Member

dai-shi commented Mar 4, 2023

I'm not sure if I understand why you can't do it in your library?

@FaberVitale
Copy link
Contributor Author

FaberVitale commented Mar 5, 2023

I'm exposing read-only and standard zustand stores and I didn't want to create a useStore wrapper with fixed types.


read-only stores

I also think that it would be cool zustand had the concept of read-only stores.

read-only stores in other libraries

derived

I've also seen that derive-zustand throws exception when you invoke setState or destroy:

wouldn't it better to type that store as ReadOnlyStoreApi<T> and remove those 2 unnecessary methods?

@dai-shi
Copy link
Member

dai-shi commented Mar 5, 2023

I mean I think you can define such utility type on your end.
It's out intention to avoid exporting types. #1589 is just using it as an internal type.
If there's a technical difficulty in your library, please open a new discussion.

I'll try it in derive-zustand too. That's good point. Thank you!

Closing this.

@dai-shi dai-shi closed this Mar 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants