Merge branch 'main' into v5

This commit is contained in:
daishi 2023-11-28 09:28:36 +09:00
commit 39928ef973
11 changed files with 940 additions and 968 deletions

View File

@ -33,8 +33,8 @@ jobs:
- 18.0.0
- 18.1.0
- 18.2.0
- 18.3.0-canary-0c6348758-20231030
- 0.0.0-experimental-0c6348758-20231030
- 18.3.0-canary-6c7b41da3-20231123
- 0.0.0-experimental-6c7b41da3-20231123
devtools-skip:
- CI-MATRIX-NOSKIP
include:

View File

@ -13,6 +13,8 @@ jobs:
fail-fast: false
matrix:
typescript:
- 5.3.2
- 5.2.2
- 5.1.6
- 5.0.4
- 4.9.5

View File

@ -33,9 +33,7 @@ Zustand is available as a package on NPM for use:
```bash
# NPM
npm install zustand
# Yarn
yarn add zustand
# Or, use any package manager of your choice.
```
## First create a store

View File

@ -1,7 +1,7 @@
{
"name": "zustand",
"private": true,
"version": "4.4.6",
"version": "4.4.7",
"publishConfig": {
"tag": "next"
},
@ -208,49 +208,49 @@
"use-sync-external-store": "1.2.0"
},
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/plugin-external-helpers": "^7.22.5",
"@babel/plugin-transform-react-jsx": "^7.22.15",
"@babel/plugin-transform-runtime": "^7.23.2",
"@babel/plugin-transform-typescript": "^7.22.15",
"@babel/preset-env": "^7.23.2",
"@redux-devtools/extension": "^3.2.5",
"@rollup/plugin-alias": "^5.0.1",
"@babel/core": "^7.23.3",
"@babel/plugin-external-helpers": "^7.23.3",
"@babel/plugin-transform-react-jsx": "^7.23.4",
"@babel/plugin-transform-runtime": "^7.23.4",
"@babel/plugin-transform-typescript": "^7.23.4",
"@babel/preset-env": "^7.23.3",
"@redux-devtools/extension": "^3.2.6",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^11.1.5",
"@testing-library/react": "^14.0.0",
"@types/react": "^18.2.33",
"@types/react-dom": "^18.2.14",
"@types/use-sync-external-store": "^0.0.5",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
"@vitest/coverage-c8": "^0.33.0",
"@testing-library/react": "^14.1.2",
"@types/react": "^18.2.39",
"@types/react-dom": "^18.2.17",
"@types/use-sync-external-store": "^0.0.6",
"@typescript-eslint/eslint-plugin": "^6.13.0",
"@typescript-eslint/parser": "^6.13.0",
"@vitest/coverage-v8": "^0.34.6",
"@vitest/ui": "^0.34.6",
"concurrently": "^8.2.2",
"downlevel-dts": "^0.11.0",
"esbuild": "^0.19.5",
"eslint": "^8.52.0",
"esbuild": "^0.19.8",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-vitest": "^0.3.8",
"eslint-plugin-vitest": "^0.3.10",
"immer": "^10.0.3",
"jsdom": "^22.1.0",
"jsdom": "^23.0.0",
"json": "^11.0.0",
"prettier": "^3.0.3",
"prettier": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"redux": "5.0.0-alpha.1",
"rollup": "^4.2.0",
"rollup": "^4.6.0",
"rollup-plugin-esbuild": "^6.1.0",
"shx": "^0.3.4",
"typescript": "^5.2.2",
"typescript": "^5.3.2",
"vitest": "^0.34.6"
},
"peerDependencies": {
@ -268,5 +268,8 @@
"react": {
"optional": true
}
},
"resolutions": {
"vite": "4.5.0"
}
}

View File

@ -164,6 +164,8 @@ const useSoundStore = create((set, get) => ({
Sometimes you need to access state in a non-reactive way or act upon the store. For these cases, the resulting hook has utility functions attached to its prototype.
:warning: This technique is not recommended for adding state in [React Server Components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md) (typically in Next.js 13 and above). It can lead to unexpected bugs and privacy issues for your users. For more details, see [#2200](https://github.com/pmndrs/zustand/discussions/2200).
```jsx
const useDogStore = create(() => ({ paw: true, snout: true, fur: true }))

View File

@ -30,22 +30,22 @@ type Write<T, U> = Omit<T, keyof U> & U
type TakeTwo<T> = T extends { length: 0 }
? [undefined, undefined]
: T extends { length: 1 }
? [...a0: Cast<T, unknown[]>, a1: undefined]
: T extends { length: 0 | 1 }
? [...a0: Cast<T, unknown[]>, a1: undefined]
: T extends { length: 2 }
? T
: T extends { length: 1 | 2 }
? T
: T extends { length: 0 | 1 | 2 }
? T
: T extends [infer A0, infer A1, ...unknown[]]
? [A0, A1]
: T extends [infer A0, (infer A1)?, ...unknown[]]
? [A0, A1?]
: T extends [(infer A0)?, (infer A1)?, ...unknown[]]
? [A0?, A1?]
: never
? [...a0: Cast<T, unknown[]>, a1: undefined]
: T extends { length: 0 | 1 }
? [...a0: Cast<T, unknown[]>, a1: undefined]
: T extends { length: 2 }
? T
: T extends { length: 1 | 2 }
? T
: T extends { length: 0 | 1 | 2 }
? T
: T extends [infer A0, infer A1, ...unknown[]]
? [A0, A1]
: T extends [infer A0, (infer A1)?, ...unknown[]]
? [A0, A1?]
: T extends [(infer A0)?, (infer A1)?, ...unknown[]]
? [A0?, A1?]
: never
type WithDevtools<S> = Write<S, StoreDevtools<S>>
@ -53,7 +53,7 @@ type StoreDevtools<S> = S extends {
setState: (...a: infer Sa) => infer Sr
}
? {
setState<A extends string | { type: unknown }>(
setState<A extends string | { type: string }>(
...a: [...a: TakeTwo<Sa>, action?: A]
): Sr
}
@ -173,12 +173,12 @@ const devtoolsImpl: DevtoolsImpl =
;(api.setState as NamedSet<S>) = (state, replace, nameOrAction) => {
const r = set(state, replace)
if (!isRecording) return r
const action: { type: unknown } =
const action: { type: string } =
nameOrAction === undefined
? { type: anonymousActionType || 'anonymous' }
: typeof nameOrAction === 'string'
? { type: nameOrAction }
: nameOrAction
? { type: nameOrAction }
: nameOrAction
if (store === undefined) {
connection?.send(action, get())
return r

View File

@ -21,16 +21,16 @@ type Write<T, U> = Omit<T, keyof U> & U
type SkipTwo<T> = T extends { length: 0 }
? []
: T extends { length: 1 }
? []
: T extends { length: 0 | 1 }
? []
: T extends [unknown, unknown, ...infer A]
? A
: T extends [unknown, unknown?, ...infer A]
? A
: T extends [unknown?, unknown?, ...infer A]
? A
: never
? []
: T extends { length: 0 | 1 }
? []
: T extends [unknown, unknown, ...infer A]
? A
: T extends [unknown, unknown?, ...infer A]
? A
: T extends [unknown?, unknown?, ...infer A]
? A
: never
type WithImmer<S> = Write<S, StoreImmer<S>>

View File

@ -3,7 +3,7 @@ import type { NamedSet } from './devtools.ts'
type Write<T, U> = Omit<T, keyof U> & U
type Action = { type: unknown }
type Action = { type: string }
type StoreRedux<A> = {
dispatch: (a: A) => A

View File

@ -20,10 +20,10 @@ type Get<T, K, F> = K extends keyof T ? T[K] : F
export type Mutate<S, Ms> = number extends Ms['length' & keyof Ms]
? S
: Ms extends []
? S
: Ms extends [[infer Mi, infer Ma], ...infer Mrs]
? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs>
: never
? S
: Ms extends [[infer Mi, infer Ma], ...infer Mrs]
? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs>
: never
export type StateCreator<
T,
@ -73,7 +73,7 @@ const createStoreImpl: CreateStoreImpl = (createState) => {
if (!Object.is(nextState, state)) {
const previousState = state
state =
replace ?? typeof nextState !== 'object'
replace ?? (typeof nextState !== 'object' || nextState === null)
? (nextState as TState)
: Object.assign({}, state, nextState)
listeners.forEach((listener) => listener(state, previousState))

View File

@ -112,6 +112,24 @@ it('can set the store without merging', () => {
expect(getState()).toEqual({ b: 2 })
})
it('can set the object store to null', () => {
const { setState, getState } = createStore<{ a: number } | null>(() => ({
a: 1,
}))
setState(null)
expect(getState()).toEqual(null)
})
it('can set the non-object store to null', () => {
const { setState, getState } = createStore<string | null>(() => 'value')
setState(null)
expect(getState()).toEqual(null)
})
it('works with non-object state', () => {
const store = createStore<number>(() => 1)
const inc = () => store.setState((c) => c + 1)

1757
yarn.lock

File diff suppressed because it is too large Load Diff