{"_id":"jotai-family","_rev":"7-2b332a29e5f415525296a04323553fc6","name":"jotai-family","dist-tags":{"latest":"1.1.0"},"versions":{"0.0.0":{"name":"jotai-family","version":"0.0.0","_id":"jotai-family@0.0.0","maintainers":[{"name":"daishi","email":"daishi@axlight.com"}],"dist":{"shasum":"da9563a6db2c615a80fb0eec77ec3777d6572ab9","tarball":"https://registry.npmjs.org/jotai-family/-/jotai-family-0.0.0.tgz","fileCount":1,"integrity":"sha512-duf38QYY9kyCimcjTFdqiEGgK2M/g7TVpXQ4PgcIygRvCqxGi4qFtsKFr/5Vee1OV7KTIj/9jEyIF0k0a5RO/w==","signatures":[{"sig":"MEQCIFpOrxjomEp6NCcfkg1ntIVPpDMpuaykdXX/G7i7X4+CAiB+10kW9hEyhbQKDu8TGz+ysc1LfeDtQLmkuQHkyMXbGA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":51},"_npmUser":{"name":"daishi","email":"daishi@axlight.com"},"_npmVersion":"9.6.7","directories":{},"_nodeVersion":"18.17.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jotai-family_0.0.0_1723425215726_0.09896254859024456","host":"s3://npm-registry-packages"}},"0.0.1":{"name":"jotai-family","version":"0.0.1","keywords":["jotai","react","family","collections","atoms"],"author":{"name":"Daishi Kato"},"license":"MIT","_id":"jotai-family@0.0.1","maintainers":[{"name":"daishi","email":"daishi@axlight.com"},{"name":"dmaskasky","email":"dmaskasky@gmail.com"}],"contributors":[{"url":"https://github.com/dai-shi","name":"Daishi Kato"}],"homepage":"https://github.com/jotaijs/jotai-family#readme","bugs":{"url":"https://github.com/jotaijs/jotai-family/issues"},"dist":{"shasum":"389c0ba6e2bf5c7911e98da5a3e3cad5dda0703f","tarball":"https://registry.npmjs.org/jotai-family/-/jotai-family-0.0.1.tgz","fileCount":31,"integrity":"sha512-IwEhsZ7XrFT350JlBLrg3onFkiE2q8xuAjHi7JvOAVMiRqSlpRU76viS4C1JQpMdHjiv+TNCrT+ZGlzcsaAUJw==","signatures":[{"sig":"MEUCIQCVUmDaeLN1SDGdgM47vl8+832eAxCfAH0Qb4OuxM8iPwIgPQLE4aExCZ1S1JJ5cWOFgR29F//YA9g79k10fbLanx8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":47619},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","source":"./src/index.ts","engines":{"node":">=12.20.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"default":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"b3090b49879c7ee862a373c91c2765086c743c11","scripts":{"fix":"pnpm run '/^fix:.*/'","test":"pnpm run \"/^test:.*/\"","compile":"rm -rf dist && pnpm run '/^compile:.*/'","pretest":"pnpm compile","fix:lint":"eslint --config ./eslint.config.ts --fix .","test:lint":"eslint .","test:spec":"vitest run","fix:format":"prettier --write .","test:types":"tsc --noEmit","compile:cjs":"tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json","compile:esm":"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json","test:format":"prettier --list-different ."},"_npmUser":{"name":"daishi","email":"daishi@axlight.com"},"repository":{"url":"git+https://github.com/jotaijs/jotai-family.git","type":"git"},"_npmVersion":"10.8.2","description":"👻👨‍👩‍👧‍👦","directories":{},"sideEffects":false,"_nodeVersion":"20.19.6","_hasShrinkwrap":false,"packageManager":"pnpm@8.15.0","devDependencies":{"jiti":"^2.6.1","vite":"^7.2.6","jotai":"2.15.2","eslint":"^9.39.1","vitest":"^4.0.15","prettier":"^3.7.4","happy-dom":"^20.0.11","tsc-alias":"^1.8.16","@eslint/js":"^9.39.1","typescript":"^5.9.3","@types/node":"^24.10.1","jotai-family":"link:","typescript-eslint":"^8.48.1","eslint-plugin-import":"2.32.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","@typescript-eslint/parser":"^8.48.1","@typescript-eslint/eslint-plugin":"^8.48.1","eslint-import-resolver-typescript":"^4.4.4"},"peerDependencies":{"jotai":">=2.9.0"},"_npmOperationalInternal":{"tmp":"tmp/jotai-family_0.0.1_1764902573411_0.6183513524746957","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"jotai-family","version":"1.0.0","keywords":["jotai","react","family","collections","atoms"],"author":{"name":"Daishi Kato"},"license":"MIT","_id":"jotai-family@1.0.0","maintainers":[{"name":"daishi","email":"daishi@axlight.com"},{"name":"dmaskasky","email":"dmaskasky@gmail.com"}],"contributors":[{"url":"https://github.com/dai-shi","name":"Daishi Kato"}],"homepage":"https://github.com/jotaijs/jotai-family#readme","bugs":{"url":"https://github.com/jotaijs/jotai-family/issues"},"dist":{"shasum":"c3add31da29e5f9132884713c6729509d0f83886","tarball":"https://registry.npmjs.org/jotai-family/-/jotai-family-1.0.0.tgz","fileCount":31,"integrity":"sha512-XcHahqRlEuF5FyB0gqgUVu7WuvKnDWNkJKBntcSUJKpEouAb1rDA1B+zEmkyas2mGtMJYyf+QAr4kI2oEIbiKQ==","signatures":[{"sig":"MEUCICdF4J3KDDU41MRjRstL4mod97blOSd0XKPYAKUtFmCaAiEAtmOpfBFsTmhVxv1HFIDyNP1yFmaOOjw5m852nrPxVdA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48860},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","source":"./src/index.ts","engines":{"node":">=12.20.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"default":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"96255f2897bf8750b3313a7aa7ce8949ffbcd43d","scripts":{"fix":"pnpm run '/^fix:.*/'","test":"pnpm run \"/^test:.*/\"","compile":"rm -rf dist && pnpm run '/^compile:.*/'","pretest":"pnpm compile","fix:lint":"eslint --config ./eslint.config.ts --fix .","test:lint":"eslint .","test:spec":"vitest run","fix:format":"prettier --write .","test:types":"tsc --noEmit","compile:cjs":"tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json","compile:esm":"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json","test:format":"prettier --list-different ."},"_npmUser":{"name":"daishi","email":"daishi@axlight.com"},"repository":{"url":"git+https://github.com/jotaijs/jotai-family.git","type":"git"},"_npmVersion":"10.8.2","description":"👻👨‍👩‍👧‍👦","directories":{},"sideEffects":false,"_nodeVersion":"20.19.6","_hasShrinkwrap":false,"packageManager":"pnpm@8.15.0","devDependencies":{"jiti":"^2.6.1","vite":"^7.2.6","jotai":"2.15.2","eslint":"^9.39.1","vitest":"^4.0.15","prettier":"^3.7.4","happy-dom":"^20.0.11","tsc-alias":"^1.8.16","@eslint/js":"^9.39.1","typescript":"^5.9.3","@types/node":"^24.10.1","jotai-family":"link:","typescript-eslint":"^8.48.1","eslint-plugin-import":"2.32.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","@typescript-eslint/parser":"^8.48.1","@typescript-eslint/eslint-plugin":"^8.48.1","eslint-import-resolver-typescript":"^4.4.4"},"peerDependencies":{"jotai":">=2.9.0"},"_npmOperationalInternal":{"tmp":"tmp/jotai-family_1.0.0_1764905762106_0.955753235560874","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"jotai-family","version":"1.0.1","keywords":["jotai","react","family","collections","atoms"],"author":{"name":"Daishi Kato"},"license":"MIT","_id":"jotai-family@1.0.1","maintainers":[{"name":"daishi","email":"daishi@axlight.com"},{"name":"dmaskasky","email":"dmaskasky@gmail.com"}],"contributors":[{"url":"https://github.com/dai-shi","name":"Daishi Kato"}],"homepage":"https://github.com/jotaijs/jotai-family#readme","bugs":{"url":"https://github.com/jotaijs/jotai-family/issues"},"dist":{"shasum":"0782aaaf22042b63111df4c1f9acf7b2ceff03cb","tarball":"https://registry.npmjs.org/jotai-family/-/jotai-family-1.0.1.tgz","fileCount":31,"integrity":"sha512-Zb/79GNDhC/z82R+6qTTpeKW4l4H6ZCApfF5W8G4SH37E4mhbysU7r8DkP0KX94hWvjB/6lt/97nSr3wB+64Zg==","signatures":[{"sig":"MEUCIGb62eVfft+ZnCjnj9AF0GMMUZh3Ss88Mw5eHh4uDDLEAiEA/Pk5Cdy9uBfk9bcIm+6ayWVCHTuTBEEghOT9+yz482M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48860},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","source":"./src/index.ts","engines":{"node":">=12.20.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"default":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"7f9f7085b185ea7960f8df7c7bdc2de4a1c08a82","scripts":{"fix":"pnpm run '/^fix:.*/'","test":"pnpm run \"/^test:.*/\"","compile":"rm -rf dist && pnpm run '/^compile:.*/'","pretest":"pnpm compile","fix:lint":"eslint --config ./eslint.config.ts --fix .","test:lint":"eslint .","test:spec":"vitest run","fix:format":"prettier --write .","test:types":"tsc --noEmit","compile:cjs":"tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json","compile:esm":"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json","test:format":"prettier --list-different ."},"_npmUser":{"name":"daishi","email":"daishi@axlight.com"},"repository":{"url":"git+https://github.com/jotaijs/jotai-family.git","type":"git"},"_npmVersion":"10.8.2","description":"👻👨‍👩‍👧‍👦","directories":{},"sideEffects":false,"_nodeVersion":"20.19.6","_hasShrinkwrap":false,"packageManager":"pnpm@8.15.0","devDependencies":{"jiti":"^2.6.1","vite":"^7.2.6","jotai":"2.16.0","eslint":"^9.39.1","vitest":"^4.0.15","prettier":"^3.7.4","happy-dom":"^20.0.11","tsc-alias":"^1.8.16","@eslint/js":"^9.39.1","typescript":"^5.9.3","@types/node":"^24.10.1","jotai-family":"link:","typescript-eslint":"^8.48.1","eslint-plugin-import":"2.32.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","@typescript-eslint/parser":"^8.48.1","@typescript-eslint/eslint-plugin":"^8.48.1","eslint-import-resolver-typescript":"^4.4.4"},"peerDependencies":{"jotai":">=2.9.0"},"_npmOperationalInternal":{"tmp":"tmp/jotai-family_1.0.1_1765316210657_0.8547028564917305","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"jotai-family","version":"1.0.2","keywords":["jotai","react","family","collections","atoms"],"author":{"name":"Daishi Kato"},"license":"MIT","_id":"jotai-family@1.0.2","maintainers":[{"name":"daishi","email":"daishi@axlight.com"},{"name":"dmaskasky","email":"dmaskasky@gmail.com"}],"contributors":[{"url":"https://github.com/dai-shi","name":"Daishi Kato"}],"homepage":"https://github.com/jotaijs/jotai-family#readme","bugs":{"url":"https://github.com/jotaijs/jotai-family/issues"},"dist":{"shasum":"11d9f88a39579aaf0d80dcd8826b8c32cf6b5269","tarball":"https://registry.npmjs.org/jotai-family/-/jotai-family-1.0.2.tgz","fileCount":31,"integrity":"sha512-U1aTMGxmsmz2Z8gaJD1/ljmMnsmG4/dqrcsfwGbjWV7p6boB9Vy3+75YwUpwPj7GbLNJk9O8rl1VNi8d7+6Rxw==","signatures":[{"sig":"MEYCIQDYJybbu6IFUEXB3rmMaqEN9HTdTCvTYHaAYCLXyORh8QIhAPdRnTG7FXNi1FSbzfft3Mk712FaSRwQcZFZIPyOO7EK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/jotai-family@1.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":48948},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","source":"./src/index.ts","engines":{"node":">=12.20.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"default":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./package.json":"./package.json"},"gitHead":"44998f88f244bacc3bab15560e3a9efa4525a80a","scripts":{"fix":"pnpm run '/^fix:.*/'","test":"pnpm run \"/^test:.*/\"","build":"rm -rf dist && pnpm run '/^build:.*/'","pretest":"pnpm build","fix:lint":"eslint --config ./eslint.config.ts --fix .","build:cjs":"tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json","build:esm":"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json","test:lint":"eslint .","test:spec":"vitest run","fix:format":"prettier --write .","test:types":"tsc --noEmit","test:format":"prettier --list-different ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2ec726af-5724-4fe3-9e46-97e9a134c33b"}},"repository":{"url":"git+https://github.com/jotaijs/jotai-family.git","type":"git"},"_npmVersion":"11.11.0","description":"👻👨‍👩‍👧‍👦","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"packageManager":"pnpm@10.18.3","devDependencies":{"jiti":"^2.6.1","vite":"^7.2.6","jotai":"2.16.0","eslint":"^9.39.1","vitest":"^4.0.15","prettier":"^3.7.4","happy-dom":"^20.0.11","tsc-alias":"^1.8.16","@eslint/js":"^9.39.1","typescript":"^5.9.3","@types/node":"^24.10.1","jotai-family":"link:","typescript-eslint":"^8.48.1","eslint-plugin-import":"2.32.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","@typescript-eslint/parser":"^8.48.1","@typescript-eslint/eslint-plugin":"^8.48.1","eslint-import-resolver-typescript":"^4.4.4"},"peerDependencies":{"jotai":">=2.9.0"},"_npmOperationalInternal":{"tmp":"tmp/jotai-family_1.0.2_1778698164969_0.14580682413518153","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"jotai-family","description":"👻👨‍👩‍👧‍👦","version":"1.1.0","type":"module","author":{"name":"Daishi Kato"},"contributors":[{"name":"Daishi Kato","url":"https://github.com/dai-shi"}],"repository":{"type":"git","url":"git+https://github.com/jotaijs/jotai-family.git"},"bugs":{"url":"https://github.com/jotaijs/jotai-family/issues"},"source":"./src/index.ts","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{"./package.json":"./package.json",".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"},"default":{"types":"./dist/index.d.ts","default":"./dist/index.js"}}},"sideEffects":false,"packageManager":"pnpm@10.18.3","scripts":{"build":"rm -rf dist && pnpm run '/^build:.*/'","build:esm":"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json","build:cjs":"tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json","fix":"pnpm run '/^fix:.*/'","fix:format":"prettier --write .","fix:lint":"eslint --config ./eslint.config.ts --fix .","pretest":"pnpm build","test":"pnpm run \"/^test:.*/\"","test:format":"prettier --list-different .","test:types":"tsc --noEmit","test:lint":"eslint .","test:spec":"vitest run"},"keywords":["jotai","react","family","collections","atoms"],"license":"MIT","devDependencies":{"@eslint/js":"^9.39.1","@types/node":"^24.10.1","@typescript-eslint/eslint-plugin":"^8.48.1","@typescript-eslint/parser":"^8.48.1","eslint":"^9.39.1","eslint-config-prettier":"^10.1.8","eslint-import-resolver-typescript":"^4.4.4","eslint-plugin-import":"2.32.0","eslint-plugin-prettier":"^5.5.4","happy-dom":"^20.0.11","jiti":"^2.6.1","jotai":"3.0.0-alpha.0","jotai-family":"link:","prettier":"^3.7.4","tsc-alias":"^1.8.16","typescript":"^5.9.3","typescript-eslint":"^8.48.1","vite":"^7.2.6","vitest":"^4.0.15"},"peerDependencies":{"jotai":">=2.9.0"},"engines":{"node":">=12.20.0"},"gitHead":"c67cbdbf8b028fb6bee752d07b80a100ce3c5427","_id":"jotai-family@1.1.0","homepage":"https://github.com/jotaijs/jotai-family#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-T1ACRsLnN5Mu0B8/DIWUW1hW7x1RmpBprm/+CWmUTf4ZZUmIFEQpBJ9PNQtXPjdUD2uu8RvwBxr7nJPdCw5BXg==","shasum":"87eab9c6e8b241f3bc39b6f04a3b55247ebd40bb","tarball":"https://registry.npmjs.org/jotai-family/-/jotai-family-1.1.0.tgz","fileCount":31,"unpackedSize":49004,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/jotai-family@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCEb4eTynoGPxEVkcLopbgWie113DSMkn2ndCXYgiJGLAIhAOsauiYv2uJGJ9IKn4x8pxhgI+Tt4v/R+d1xkAGnERai"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:2ec726af-5724-4fe3-9e46-97e9a134c33b"}},"directories":{},"maintainers":[{"name":"daishi","email":"daishi@axlight.com"},{"name":"dmaskasky","email":"dmaskasky@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jotai-family_1.1.0_1785338347126_0.504590376753411"},"_hasShrinkwrap":false}},"time":{"created":"2024-08-12T01:13:35.725Z","modified":"2026-07-29T15:19:07.599Z","0.0.0":"2024-08-12T01:13:35.938Z","0.0.1":"2025-12-05T02:42:53.639Z","1.0.0":"2025-12-05T03:36:02.254Z","1.0.1":"2025-12-09T21:36:50.804Z","1.0.2":"2026-05-13T18:49:25.172Z","1.1.0":"2026-07-29T15:19:07.279Z"},"bugs":{"url":"https://github.com/jotaijs/jotai-family/issues"},"author":{"name":"Daishi Kato"},"license":"MIT","homepage":"https://github.com/jotaijs/jotai-family#readme","keywords":["jotai","react","family","collections","atoms"],"repository":{"type":"git","url":"git+https://github.com/jotaijs/jotai-family.git"},"description":"👻👨‍👩‍👧‍👦","contributors":[{"name":"Daishi Kato","url":"https://github.com/dai-shi"}],"maintainers":[{"name":"daishi","email":"daishi@axlight.com"},{"name":"dmaskasky","email":"dmaskasky@gmail.com"}],"readme":"# jotai-family\n\n[jotai-family](https://github.com/jotaijs/jotai-family) is a package for atom collections.\n\n## atomFamily\n\n### Usage\n\n```js\natomFamily(initializeAtom, areEqual): (param) => Atom\n```\n\nThis will create a function that takes `param` and returns an atom.\nIf the atom has already been created, it will be returned from the cache.\n`initializeAtom` is a function that can return any kind of atom (`atom()`, `atomWithDefault()`, ...).\nNote that the `areEqual` argument is optional and compares\nif two params are equal (defaults to `Object.is`).\n\nTo reproduce behavior similar to [Recoil's atomFamily/selectorFamily](https://recoiljs.org/docs/api-reference/utils/atomFamily),\nspecify a deepEqual function to `areEqual`. For example:\n\n```js\nimport { atom } from 'jotai'\nimport { atomFamily } from 'jotai-family'\nimport deepEqual from 'fast-deep-equal'\n\nconst fooFamily = atomFamily((param) => atom(param), deepEqual)\n```\n\n### TypeScript\n\nThe atom family types will be inferred from initializeAtom. Here's a typical usage with a primitive atom.\n\n```ts\nimport type { PrimitiveAtom } from 'jotai'\n\n/**\n * here the atom(id) returns a PrimitiveAtom<number>\n * and PrimitiveAtom<number> is a WritableAtom<number, SetStateAction<number>>\n */\nconst myFamily = atomFamily((id: number) => atom(id))\n```\n\nYou can explicitly declare the type of parameter and atom type using TypeScript generics.\n\n```ts\natomFamily<Param, AtomType extends Atom<unknown>>(\n  initializeAtom: (param: Param) => AtomType,\n  areEqual?: (a: Param, b: Param) => boolean\n): AtomFamily<Param, AtomType>\n```\n\nExample with explicit types:\n\n```ts\nimport { atom } from 'jotai'\nimport type { PrimitiveAtom } from 'jotai'\nimport { atomFamily } from 'jotai-family'\n\nconst myFamily = atomFamily<number, PrimitiveAtom<number>>(\n  (id: number) => atom(id)\n)\n```\n\n### Caveat: Memory Leaks\n\nInternally, atomFamily is just a Map whose key is a param and whose value is an atom config.\nUnless you explicitly remove unused params, this leads to memory leaks.\nThis is crucial if you use infinite number of params.\n\nThere are several methods available:\n\n#### `myFamily.remove(param)`\nRemoves a specific param from the cache.\n\n#### `myFamily.setShouldRemove(shouldRemove)`\nRegisters a `shouldRemove` function which runs immediately **and** when you are to get an atom from a cache.\n- `shouldRemove` is a function that takes two arguments `createdAt` in milliseconds and `param`, and returns a boolean value.\n- Setting `null` will remove the previously registered function.\n\n#### `myFamily.getParams()`\nReturns an iterable of all params currently in the cache.\n\n```ts\nconst myFamily = atomFamily((id: number) => atom(id))\nmyFamily(1)\nmyFamily(2)\nmyFamily(3)\nArray.from(myFamily.getParams()) // [1, 2, 3]\n```\n\n#### `myFamily.unstable_listen(callback)`\nRegisters a callback that fires when an atom is created or removed. Returns a cleanup function.\n- **Note**: This API is for advanced use cases and can change without notice.\n\n```ts\nconst myFamily = atomFamily((id: number) => atom(id))\nconst unsubscribe = myFamily.unstable_listen((event) => {\n  console.log(event.type) // 'CREATE' or 'REMOVE'\n  console.log(event.param) // the param\n  console.log(event.atom) // the atom instance\n})\n\nmyFamily(1) // logs: CREATE, 1, <atom>\nmyFamily.remove(1) // logs: REMOVE, 1, <atom>\n\nunsubscribe() // stop listening\n```\n\n### Examples\n\n```js\nimport { atom } from 'jotai'\nimport { atomFamily } from 'jotai-family'\n\nconst todoFamily = atomFamily((name) => atom(name))\n\ntodoFamily('foo')\n// this will create a new atom('foo'), or return the one if already created\n```\n\n```js\nimport { atom } from 'jotai'\nimport { atomFamily } from 'jotai-family'\n\nconst todoFamily = atomFamily((name) =>\n  atom(\n    (get) => get(todosAtom)[name],\n    (get, set, arg) => {\n      const prev = get(todosAtom)\n      set(todosAtom, { ...prev, [name]: { ...prev[name], ...arg } })\n    },\n  ),\n)\n```\n\n```js\nimport { atom } from 'jotai'\nimport { atomFamily } from 'jotai-family'\n\nconst todoFamily = atomFamily(\n  ({ id, name }) => atom({ name }),\n  (a, b) => a.id === b.id,\n)\n```\n\n### Codesandbox\n\n<CodeSandbox id=\"23lgqf\" />\n\n---\n\n## atomTree\n\nThe **atomTree** utility provides a hierarchical way to create, reuse, and remove Jotai atoms. Each atom is associated with a unique path, which is an array of unknown types. When you request the same path multiple times, `atomTree` ensures that the same atom instance is returned. You can also remove a specific atom or an entire subtree of atoms when they are no longer needed.\n\nUse `atomTree` when you anticipate a large number of potential paths and want to:\n\n- **Reuse the same atom** for repeated paths.  \n- **Clean up** unwanted atoms easily, including entire subtrees.\n\n```js\nimport { atom } from 'jotai'\nimport { atomTree } from 'jotai-family'\n\n// Create a tree instance, passing a factory function\n// that takes a path array and returns a new atom.\nconst tree = atomTree((path) => atom(path.join('-')))\n\n// Create or retrieve the atom at ['foo', 'bar']\nconst atomA = tree(['foo', 'bar'])\nconst atomB = tree(['foo', 'bar'])\n\n// atomA and atomB are the same instance.\nconsole.log(atomA === atomB) // true\n\n// Remove the atom at ['foo', 'bar']\n// (and optionally remove its entire subtree)\ntree.remove(['foo', 'bar'])\n```\n\n### API\n\n#### Creating the tree\n\nCreates a new hierarchical tree of Jotai atoms. It accepts a **initializePathAtom** function that receives a path array and returns an atom. The returned function can be used to create, retrieve, and remove atoms at specific paths.\n\n```ts\nfunction atomTree<Path, AtomType>(\n  initializePathAtom: (path: Path) => AtomType\n): {\n  (path: Path): AtomType\n  remove(path: Path, removeSubTree?: boolean): void\n  getSubTree(path: Path): Node<AtomType>\n  getNodePath(path: Path): Node<AtomType>[]\n}\n\ntype Node<AtomType> = {\n  atom?: AtomType\n  children?: Map<PathSegment, Node<AtomType>>\n}\n```\n\n### Creating Path Atoms\n```ts\ntree(path: Path): AtomType\n```\nCreates (or retrieves) an atom at the specified path. Subsequent calls with the same path return the same atom instance.\n\n### Removing Path Atoms\n```ts\ntree.remove(path: Path, removeSubTree = false): void\n```\nRemoves the atom at the specified path. If `removeSubTree` is `true`, all child paths under that path are also removed.\n\nThis method removes the atom at the specified path. If `removeSubTree` is `true`, it also removes all child paths under that path.\n\n### Retrieving A Subtree\n```ts\ntree.getSubTree(path: Path): Node<AtomType>\n```\n\nRetrieves the internal node representing the specified path. This is useful for inspecting the tree structure. **Throws an error if the path does not exist.** The node structure is as follows:\n\n```ts\ntype Node<AtomType> = {\n  atom?: AtomType\n  children?: Map<PathSegment, Node<AtomType>>\n}\n```\n\n### Retrieving A Node Path\n```ts\ntree.getNodePath(path: Path): Node<AtomType>[]\n```\nReturns an array of node objects from the root node to the node at the specified path, inclusive.\n\n## Usage Example\n\n```js\nimport { atom } from 'jotai'\nimport { atomTree } from 'jotai-family'\n\nconst btree = atomTree((path) => atom(`Data for path: ${path}`))\n\n// Create or retrieve the atom at [true, false]\nconst userAtom = btree([true, false])\n\nconsole.log(store.get(userAtom)) // 'Data for path: true,false'\n\n// Remove the atom (and optionally remove its subtree)\nbtree.remove([true,false])\n```\n","readmeFilename":"README.md"}