Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: pmndrs/jotai
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.7.1
Choose a base ref
...
head repository: pmndrs/jotai
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.7.2
Choose a head ref
  • 6 commits
  • 19 files changed
  • 3 contributors

Commits on Mar 29, 2024

  1. refactor(vanilla): moved (un)mount guards into their respective funct…

    …ions. (suggestion) (#2457)
    iwoplaza authored Mar 29, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    thaJeztah Sebastiaan van Stijn
    Copy the full SHA
    b74d6d1 View commit details
  2. fix(store): improve dual instance warning in DEV (#2462)

    dai-shi authored Mar 29, 2024
    Copy the full SHA
    dbed0aa View commit details
  3. refactor: no-any (#2471)

    dai-shi authored Mar 29, 2024
    Copy the full SHA
    42f324c View commit details
  4. fix: avoid slow types (#2472)

    dai-shi authored Mar 29, 2024
    Copy the full SHA
    3aec347 View commit details
  5. chore(deps): update dev dependencies (#2473)

    * chore(deps): update dev dependencies
    
    * revert types/react
    
    * downgrade react canary/exp
    
    * revert more
    
    * revert more
    
    * downgrade react canary/exp
    
    * downgrade react canary/exp
    
    * downgrade react canary/exp
    dai-shi authored Mar 29, 2024
    Copy the full SHA
    fb9d2f0 View commit details
  6. 2.7.2

    dai-shi committed Mar 29, 2024
    Copy the full SHA
    ee631fa View commit details
4 changes: 2 additions & 2 deletions .github/workflows/test-multiple-versions.yml
Original file line number Diff line number Diff line change
@@ -33,8 +33,8 @@ jobs:
- 18.0.0
- 18.1.0
- 18.2.0
- 18.3.0-canary-56e20051c-20240311
- 0.0.0-experimental-56e20051c-20240311
- 18.3.0-canary-4b84f1161-20240318
- 0.0.0-experimental-4b84f1161-20240318
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
31 changes: 16 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "jotai",
"private": true,
"version": "2.7.1",
"version": "2.7.2",
"description": "👻 Primitive and flexible state management for React",
"main": "./index.js",
"types": "./index.d.ts",
@@ -113,10 +113,10 @@
},
"homepage": "https://github.com/pmndrs/jotai",
"devDependencies": {
"@babel/core": "^7.24.0",
"@babel/core": "^7.24.3",
"@babel/plugin-transform-react-jsx": "^7.23.4",
"@babel/plugin-transform-typescript": "^7.23.6",
"@babel/preset-env": "^7.24.0",
"@babel/plugin-transform-typescript": "^7.24.1",
"@babel/preset-env": "^7.24.3",
"@babel/template": "^7.24.0",
"@babel/types": "^7.24.0",
"@redux-devtools/extension": "^3.3.0",
@@ -127,14 +127,14 @@
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^11.1.6",
"@testing-library/dom": "^9.3.4",
"@testing-library/react": "^14.2.1",
"@testing-library/react": "^14.2.2",
"@testing-library/user-event": "14.4.3",
"@types/babel__core": "^7.20.5",
"@types/node": "^20.11.27",
"@types/node": "^20.11.30",
"@types/react": "18.2.56",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@types/react-dom": "^18.2.23",
"@typescript-eslint/eslint-plugin": "7.2.0",
"@typescript-eslint/parser": "7.2.0",
"@vitest/coverage-v8": "0.33.0",
"@vitest/ui": "0.33.0",
"benny": "^3.7.1",
@@ -146,29 +146,30 @@
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-vitest": "^0.3.26",
"eslint-plugin-vitest": "^0.4.0",
"jsdom": "^24.0.0",
"json": "^11.0.0",
"prettier": "^3.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"redux": "^5.0.1",
"rollup": "^4.13.0",
"rollup-plugin-banner2": "^1.2.2",
"rollup": "^4.13.2",
"rollup-plugin-banner2": "^1.2.3",
"rollup-plugin-esbuild": "^6.1.1",
"rxjs": "^7.8.1",
"shx": "^0.3.4",
"ts-expect": "^1.3.0",
"ts-node": "^10.9.2",
"tslib": "^2.6.2",
"typescript": "^5.4.2",
"typescript": "^5.4.3",
"vitest": "0.33.0",
"wonka": "^6.3.4"
},
"resolutions": {
"@types/react": "18.2.56"
"@types/react": "18.2.56",
"@typescript-eslint/utils": "7.2.0"
},
"peerDependencies": {
"@types/react": ">=17.0.0",
5 changes: 4 additions & 1 deletion src/react/Provider.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,10 @@ import { createStore, getDefaultStore } from '../vanilla.ts'

type Store = ReturnType<typeof createStore>

const StoreContext = createContext<Store | undefined>(undefined)
type StoreContextType = ReturnType<typeof createContext<Store | undefined>>
const StoreContext: StoreContextType = createContext<Store | undefined>(
undefined,
)

type Options = {
store?: Store
6 changes: 4 additions & 2 deletions src/react/useAtom.ts
Original file line number Diff line number Diff line change
@@ -29,15 +29,17 @@ export function useAtom<Value>(
options?: Options,
): [Awaited<Value>, never]

export function useAtom<AtomType extends WritableAtom<any, any[], any>>(
export function useAtom<
AtomType extends WritableAtom<unknown, never[], unknown>,
>(
atom: AtomType,
options?: Options,
): [
Awaited<ExtractAtomValue<AtomType>>,
SetAtom<ExtractAtomArgs<AtomType>, ExtractAtomResult<AtomType>>,
]

export function useAtom<AtomType extends Atom<any>>(
export function useAtom<AtomType extends Atom<unknown>>(
atom: AtomType,
options?: Options,
): [Awaited<ExtractAtomValue<AtomType>>, never]
2 changes: 1 addition & 1 deletion src/react/useAtomValue.ts
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ export function useAtomValue<Value>(
options?: Options,
): Awaited<Value>

export function useAtomValue<AtomType extends Atom<any>>(
export function useAtomValue<AtomType extends Atom<unknown>>(
atom: AtomType,
options?: Options,
): Awaited<ExtractAtomValue<AtomType>>
4 changes: 3 additions & 1 deletion src/react/useSetAtom.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,9 @@ export function useSetAtom<Value, Args extends unknown[], Result>(
options?: Options,
): SetAtom<Args, Result>

export function useSetAtom<AtomType extends WritableAtom<any, any[], any>>(
export function useSetAtom<
AtomType extends WritableAtom<unknown, never[], unknown>,
>(
atom: AtomType,
options?: Options,
): SetAtom<ExtractAtomArgs<AtomType>, ExtractAtomResult<AtomType>>
6 changes: 3 additions & 3 deletions src/react/utils/useHydrateAtoms.ts
Original file line number Diff line number Diff line change
@@ -5,11 +5,11 @@ type Store = ReturnType<typeof useStore>
type Options = Parameters<typeof useStore>[0] & {
dangerouslyForceHydrate?: boolean
}
type AnyWritableAtom = WritableAtom<unknown, any[], any>
type AnyWritableAtom = WritableAtom<unknown, never[], unknown>

type InferAtomTuples<T> = {
[K in keyof T]: T[K] extends readonly [infer A, unknown]
? A extends WritableAtom<unknown, infer Args, any>
? A extends WritableAtom<unknown, infer Args, infer _Result>
? readonly [A, Args[0]]
: T[K]
: never
@@ -43,7 +43,7 @@ export function useHydrateAtoms<
for (const [atom, value] of values) {
if (!hydratedSet.has(atom) || options?.dangerouslyForceHydrate) {
hydratedSet.add(atom)
store.set(atom, value)
store.set(atom, value as never)
}
}
}
6 changes: 3 additions & 3 deletions src/react/utils/useResetAtom.ts
Original file line number Diff line number Diff line change
@@ -5,10 +5,10 @@ import type { WritableAtom } from '../../vanilla.ts'

type Options = Parameters<typeof useSetAtom>[1]

export function useResetAtom(
anAtom: WritableAtom<unknown, [typeof RESET], unknown>,
export function useResetAtom<T>(
anAtom: WritableAtom<unknown, [typeof RESET], T>,
options?: Options,
) {
): () => T {
const setAtom = useSetAtom(anAtom, options)
const resetAtom = useCallback(() => setAtom(RESET), [setAtom])
return resetAtom
129 changes: 57 additions & 72 deletions src/vanilla/store.ts
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ type OnUnmount = () => void
type Getter = Parameters<AnyAtom['read']>[0]
type Setter = Parameters<AnyWritableAtom['write']>[1]

const isSelfAtom = (atom: AnyAtom, a: AnyAtom) =>
const isSelfAtom = (atom: AnyAtom, a: AnyAtom): boolean =>
atom.unstable_is ? atom.unstable_is(a) : a === atom

const hasInitialValue = <T extends Atom<AnyValue>>(
@@ -20,7 +20,7 @@ const isActuallyWritableAtom = (atom: AnyAtom): atom is AnyWritableAtom =>
!!(atom as AnyWritableAtom).write

type CancelPromise = (next?: Promise<unknown>) => void
const cancelPromiseMap = new WeakMap<Promise<unknown>, CancelPromise>()
const cancelPromiseMap: WeakMap<Promise<unknown>, CancelPromise> = new WeakMap()

const registerCancelPromise = (
promise: Promise<unknown>,
@@ -124,6 +124,8 @@ type Mounted = {
u?: OnUnmount
}

type MountedAtoms = Set<AnyAtom>

// for debugging purpose only
type StoreListenerRev2 = (
action:
@@ -134,7 +136,19 @@ type StoreListenerRev2 = (
| { type: 'restore'; flushed: Set<AnyAtom> },
) => void

type MountedAtoms = Set<AnyAtom>
type Store = {
get: <Value>(atom: Atom<Value>) => Value
set: <Value, Args extends unknown[], Result>(
atom: WritableAtom<Value, Args, Result>,
...args: Args
) => Result
sub: (atom: AnyAtom, listener: () => void) => () => void
dev_subscribe_store?: (l: StoreListenerRev2, rev: 2) => () => void
dev_get_mounted_atoms?: () => IterableIterator<AnyAtom>
dev_get_atom_state?: (a: AnyAtom) => AtomState | undefined
dev_get_mounted?: (a: AnyAtom) => Mounted | undefined
dev_restore_atoms?: (values: Iterable<readonly [AnyAtom, AnyValue]>) => void
}

/**
* Create a new store. Each store is an independent, isolated universe of atom
@@ -152,7 +166,7 @@ type MountedAtoms = Set<AnyAtom>
*
* @returns A store.
*/
export const createStore = () => {
export const createStore = (): Store => {
const atomStateMap = new WeakMap<AnyAtom, AtomState>()
const mountedMap = new WeakMap<AnyAtom, Mounted>()
const pendingStack: Set<AnyAtom>[] = []
@@ -459,7 +473,7 @@ export const createStore = () => {
},
}
try {
const valueOrPromise = atom.read(getter, options as any)
const valueOrPromise = atom.read(getter, options as never)
return setAtomValueOrPromise(atom, valueOrPromise, nextDependencies, () =>
controller?.abort(),
)
@@ -473,26 +487,6 @@ export const createStore = () => {
const readAtom = <Value>(atom: Atom<Value>): Value =>
returnAtomValue(readAtomState(atom))

const addAtom = (atom: AnyAtom): Mounted => {
let mounted = mountedMap.get(atom)
if (!mounted) {
mounted = mountAtom(atom)
}
return mounted
}

// FIXME doesn't work with mutually dependent atoms
const canUnmountAtom = (atom: AnyAtom, mounted: Mounted) =>
!mounted.l.size &&
(!mounted.t.size || (mounted.t.size === 1 && mounted.t.has(atom)))

const delAtom = (atom: AnyAtom): void => {
const mounted = mountedMap.get(atom)
if (mounted && canUnmountAtom(atom, mounted)) {
unmountAtom(atom)
}
}

const recomputeDependents = (atom: AnyAtom): void => {
const getDependents = (a: AnyAtom): Dependents => {
const dependents = new Set(mountedMap.get(a)?.t)
@@ -615,16 +609,19 @@ export const createStore = () => {
initialDependent?: AnyAtom,
onMountQueue?: (() => void)[],
): Mounted => {
const existingMount = mountedMap.get(atom)
if (existingMount) {
if (initialDependent) {
existingMount.t.add(initialDependent)
}
return existingMount
}

const queue = onMountQueue || []
// mount dependencies before mounting self
getAtomState(atom)?.d.forEach((_, a) => {
const aMounted = mountedMap.get(a)
if (aMounted) {
aMounted.t.add(atom) // add dependent
} else {
if (a !== atom) {
mountAtom(a, atom, queue)
}
if (a !== atom) {
mountAtom(a, atom, queue)
}
})
// recompute atom state
@@ -654,9 +651,17 @@ export const createStore = () => {
return mounted
}

const unmountAtom = <Value>(atom: Atom<Value>): void => {
// FIXME doesn't work with mutually dependent atoms
const canUnmountAtom = (atom: AnyAtom, mounted: Mounted) =>
!mounted.l.size &&
(!mounted.t.size || (mounted.t.size === 1 && mounted.t.has(atom)))

const tryUnmountAtom = <Value>(atom: Atom<Value>, mounted: Mounted): void => {
if (!canUnmountAtom(atom, mounted)) {
return
}
// unmount self
const onUnmount = mountedMap.get(atom)?.u
const onUnmount = mounted.u
if (onUnmount) {
onUnmount()
}
@@ -673,12 +678,10 @@ export const createStore = () => {
}
atomState.d.forEach((_, a) => {
if (a !== atom) {
const mounted = mountedMap.get(a)
if (mounted) {
mounted.t.delete(atom)
if (canUnmountAtom(a, mounted)) {
unmountAtom(a)
}
const mountedDep = mountedMap.get(a)
if (mountedDep) {
mountedDep.t.delete(atom)
tryUnmountAtom(a, mountedDep)
}
}
})
@@ -707,20 +710,12 @@ export const createStore = () => {
}
})
depSet.forEach((a) => {
const mounted = mountedMap.get(a)
if (mounted) {
mounted.t.add(atom) // add to dependents
} else if (mountedMap.has(atom)) {
// we mount dependencies only when atom is already mounted
// Note: we should revisit this when you find other issues
// https://github.com/pmndrs/jotai/issues/942
mountAtom(a, atom)
}
mountAtom(a, atom)
})
maybeUnmountAtomSet.forEach((a) => {
const mounted = mountedMap.get(a)
if (mounted && canUnmountAtom(a, mounted)) {
unmountAtom(a)
if (mounted) {
tryUnmountAtom(a, mounted)
}
})
}
@@ -784,7 +779,7 @@ export const createStore = () => {
}

const subscribeAtom = (atom: AnyAtom, listener: () => void) => {
const mounted = addAtom(atom)
const mounted = mountAtom(atom)
const flushed = flushPending([atom])
const listeners = mounted.l
listeners.add(listener)
@@ -795,7 +790,7 @@ export const createStore = () => {
}
return () => {
listeners.delete(listener)
delAtom(atom)
tryUnmountAtom(atom, mounted)
if (import.meta.env?.MODE !== 'production') {
// devtools uses this to detect if it _can_ unmount or not
storeListenersRev2.forEach((l) => l({ type: 'unsub' }))
@@ -843,29 +838,19 @@ export const createStore = () => {
}
}

type Store = ReturnType<typeof createStore>

let defaultStore: Store | undefined

if (import.meta.env?.MODE !== 'production') {
if (typeof (globalThis as any).__NUMBER_OF_JOTAI_INSTANCES__ === 'number') {
++(globalThis as any).__NUMBER_OF_JOTAI_INSTANCES__
} else {
;(globalThis as any).__NUMBER_OF_JOTAI_INSTANCES__ = 1
}
}

export const getDefaultStore = () => {
export const getDefaultStore = (): Store => {
if (!defaultStore) {
if (
import.meta.env?.MODE !== 'production' &&
(globalThis as any).__NUMBER_OF_JOTAI_INSTANCES__ !== 1
) {
console.warn(
'Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044',
)
}
defaultStore = createStore()
if (import.meta.env?.MODE !== 'production') {
;(globalThis as any).__JOTAI_DEFAULT_STORE__ ||= defaultStore
if ((globalThis as any).__JOTAI_DEFAULT_STORE__ !== defaultStore) {
console.warn(
'Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044',
)
}
}
}
return defaultStore
}
8 changes: 6 additions & 2 deletions src/vanilla/typeUtils.ts
Original file line number Diff line number Diff line change
@@ -9,9 +9,13 @@ export type ExtractAtomValue<AtomType> =
AtomType extends Atom<infer Value> ? Value : never

export type ExtractAtomArgs<AtomType> =
AtomType extends WritableAtom<any, infer Args, any> ? Args : never
AtomType extends WritableAtom<unknown, infer Args, infer _Result>
? Args
: never

export type ExtractAtomResult<AtomType> =
AtomType extends WritableAtom<any, any[], infer Result> ? Result : never
AtomType extends WritableAtom<unknown, infer _Args, infer Result>
? Result
: never

export type SetStateAction<Value> = ExtractAtomArgs<PrimitiveAtom<Value>>[0]
6 changes: 0 additions & 6 deletions src/vanilla/utils/atomWithObservable.ts
Original file line number Diff line number Diff line change
@@ -4,12 +4,6 @@ import type { Atom, Getter, WritableAtom } from '../../vanilla.ts'
type Timeout = ReturnType<typeof setTimeout>
type AnyError = unknown

declare global {
interface SymbolConstructor {
readonly observable: symbol
}
}

type Subscription = {
unsubscribe: () => void
}
2 changes: 1 addition & 1 deletion src/vanilla/utils/atomWithReducer.ts
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ export function atomWithReducer<Value, Action>(
initialValue: Value,
reducer: (value: Value, action: Action) => Value,
) {
return atom(initialValue, function (this: any, get, set, action: Action) {
return atom(initialValue, function (this: never, get, set, action: Action) {
set(this, reducer(get(this), action))
})
}
2 changes: 1 addition & 1 deletion src/vanilla/utils/atomWithRefresh.ts
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ export function atomWithRefresh<Value, Args extends unknown[], Result>(
return atom(
(get, options) => {
get(refreshAtom)
return read(get, options as any)
return read(get, options as never)
},
(get, set, ...args: Args) => {
if (args.length === 0) {
5 changes: 4 additions & 1 deletion src/vanilla/utils/atomWithReset.ts
Original file line number Diff line number Diff line change
@@ -13,7 +13,10 @@ type WithInitialValue<Value> = {
init: Value
}

export function atomWithReset<Value>(initialValue: Value) {
export function atomWithReset<Value>(
initialValue: Value,
): WritableAtom<Value, [SetStateActionWithReset<Value>], void> &
WithInitialValue<Value> {
type Update = SetStateActionWithReset<Value>
const anAtom = atom<Value, [Update], void>(
initialValue,
12 changes: 6 additions & 6 deletions src/vanilla/utils/atomWithStorage.ts
Original file line number Diff line number Diff line change
@@ -73,7 +73,7 @@ export function withStorageValidator<Value>(
return validate(value)
},
}
return storage as any // FIXME better way to type this?
return storage
}
}

@@ -113,7 +113,7 @@ export function createJSONStorage<Value>(
options?: JsonStorageOptions,
): AsyncStorage<Value> | SyncStorage<Value> {
let lastStr: string | undefined
let lastValue: any
let lastValue: Value
const storage: AsyncStorage<Value> | SyncStorage<Value> = {
getItem: (key, initialValue) => {
const parse = (str: string | null) => {
@@ -130,9 +130,9 @@ export function createJSONStorage<Value>(
}
const str = getStringStorage()?.getItem(key) ?? null
if (isPromiseLike(str)) {
return str.then(parse)
return str.then(parse) as never
}
return parse(str)
return parse(str) as never
},
setItem: (key, newValue) =>
getStringStorage()?.setItem(
@@ -197,7 +197,7 @@ export function atomWithStorage<Value>(
| SyncStorage<Value>
| AsyncStorage<Value> = defaultStorage as SyncStorage<Value>,
options?: { getOnInit?: boolean },
): any {
) {
const getOnInit = options?.getOnInit
const baseAtom = atom(
getOnInit
@@ -244,5 +244,5 @@ export function atomWithStorage<Value>(
},
)

return anAtom
return anAtom as never
}
20 changes: 10 additions & 10 deletions src/vanilla/utils/freezeAtom.ts
Original file line number Diff line number Diff line change
@@ -5,38 +5,38 @@ const cache1 = new WeakMap()
const memo1 = <T>(create: () => T, dep1: object): T =>
(cache1.has(dep1) ? cache1 : cache1.set(dep1, create())).get(dep1)

const deepFreeze = (obj: any) => {
const deepFreeze = (obj: unknown) => {
if (typeof obj !== 'object' || obj === null) return
Object.freeze(obj)
const propNames = Object.getOwnPropertyNames(obj)
for (const name of propNames) {
const value = obj[name]
const value = (obj as never)[name]
deepFreeze(value)
}
return obj
}

export function freezeAtom<AtomType extends Atom<any>>(
export function freezeAtom<AtomType extends Atom<unknown>>(
anAtom: AtomType,
): AtomType {
return memo1(() => {
const frozenAtom: any = atom(
const frozenAtom = atom(
(get) => deepFreeze(get(anAtom)),
(_get, set, arg) => set(anAtom as any, arg),
(_get, set, arg) => set(anAtom as never, arg),
)
return frozenAtom
return frozenAtom as never
}, anAtom)
}

export function freezeAtomCreator<
CreateAtom extends (...params: any[]) => Atom<any>,
>(createAtom: CreateAtom) {
return ((...params: any[]) => {
CreateAtom extends (...params: never[]) => Atom<unknown>,
>(createAtom: CreateAtom): CreateAtom {
return ((...params: never[]) => {
const anAtom = createAtom(...params)
const origRead = anAtom.read
anAtom.read = function (get, options) {
return deepFreeze(origRead.call(this, get, options))
}
return anAtom
}) as CreateAtom
}) as never
}
10 changes: 5 additions & 5 deletions src/vanilla/utils/splitAtom.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ const isWritable = <Value, Args extends unknown[], Result>(
): atom is WritableAtom<Value, Args, Result> =>
!!(atom as WritableAtom<Value, Args, Result>).write

const isFunction = <T>(x: T): x is T & ((...args: any[]) => any) =>
const isFunction = <T>(x: T): x is T & ((...args: never[]) => unknown) =>
typeof x === 'function'

type SplitAtomAction<Item> =
@@ -94,7 +94,7 @@ export function splitAtom<Item, Key>(
}
throw new Error('splitAtom: index out of bounds for read')
}
return currArr[index] as Item
return currArr[index]!
}
const write = (
get: Getter,
@@ -109,7 +109,7 @@ export function splitAtom<Item, Key>(
throw new Error('splitAtom: index out of bounds for write')
}
const nextItem = isFunction(update)
? update(arr[index] as Item)
? (update as (prev: Item) => Item)(arr[index]!)
: update
if (!Object.is(arr[index], nextItem)) {
set(arrAtom as WritableAtom<Item[], [Item[]], void>, [
@@ -190,13 +190,13 @@ export function splitAtom<Item, Key>(
set(arrAtom as WritableAtom<Item[], [Item[]], void>, [
...arr.slice(0, index1),
...arr.slice(index1 + 1, index2),
arr[index1] as Item,
arr[index1]!,
...arr.slice(index2),
])
} else {
set(arrAtom as WritableAtom<Item[], [Item[]], void>, [
...arr.slice(0, index2),
arr[index1] as Item,
arr[index1]!,
...arr.slice(index2, index1),
...arr.slice(index1 + 1),
])
2 changes: 1 addition & 1 deletion src/vanilla/utils/unwrap.ts
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ export function unwrap<Value, PendingValue>(

export function unwrap<Value, Args extends unknown[], Result, PendingValue>(
anAtom: WritableAtom<Value, Args, Result> | Atom<Value>,
fallback: (prev?: Awaited<Value>) => PendingValue = defaultFallback as any,
fallback: (prev?: Awaited<Value>) => PendingValue = defaultFallback as never,
) {
return memo2(
() => {
1,508 changes: 769 additions & 739 deletions yarn.lock

Large diffs are not rendered by default.