{"_id":"reselect","_rev":"136-210a789e404047e6d1ed78c947a4034f","name":"reselect","description":"Selectors for Redux.","dist-tags":{"rc1":"3.0.0-beta.1","alpha":"5.0.0-alpha.2","beta":"5.0.0-beta.1","next":"5.0.0-rc.0","rc":"5.0.0-rc.1","latest":"5.1.1"},"versions":{"0.0.1":{"name":"reselect","version":"0.0.1","keywords":["react","redux"],"author":"","license":"MIT","_id":"reselect@0.0.1","maintainers":[{"name":"faassen","email":"faassen@startifact.com"}],"dist":{"shasum":"26bfe760e533051d0aa8bdf1d9ed1f8591de1e77","tarball":"https://registry.npmjs.org/reselect/-/reselect-0.0.1.tgz","integrity":"sha512-FU4HQMVRjuFP7TG/sFeSWylIYhGakox7sdSGw00qPsNU/osz78a6586GnBADM4QiaId0IwFZaKmdfiQeTq+AgA==","signatures":[{"sig":"MEUCIQDCDjHA0x5VgaLdCHxj9yHcon4EqvLRONyilnCKpT0CZQIgXiQji0aqQ8oeosnAOiNUhkA5IIxzo4ghibmOExluw/A=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib"],"_shasum":"26bfe760e533051d0aa8bdf1d9ed1f8591de1e77","gitHead":"5ccfa0cc680a52b6bf675aecaa15476b057db44c","scripts":{"test":"mocha --compilers js:babel/register --ui tdd","compile":"babel -d lib/ src/","prepublish":"npm run compile"},"_npmUser":{"name":"faassen","email":"faassen@startifact.com"},"_npmVersion":"2.5.1","description":"Selectors for Redux Flux.","directories":{},"_nodeVersion":"0.12.0","devDependencies":{"chai":"^3.0.0","mocha":"^2.2.5","babel-core":"^5.6.15"}},"0.0.2":{"name":"reselect","version":"0.0.2","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@0.0.2","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"}],"homepage":"https://github.com/faassen/reselect#readme","bugs":{"url":"https://github.com/faassen/reselect/issues"},"dist":{"shasum":"d12676787ac17f8e9cfb71febb0d12a492dcb889","tarball":"https://registry.npmjs.org/reselect/-/reselect-0.0.2.tgz","integrity":"sha512-ugmxjgc/Lx6oL+DXUpg4Mszfl4B92fKL4aCtWfmPXz/XUA3AyTB60yg9MCdZhZlMfOwZ8TFAZVaY0C1a41Q9qA==","signatures":[{"sig":"MEQCIDzl/thuKHrNw2j0K5x2BBNUoQHE53MVi7j+24YalBHhAiB82goyIX/xhIQHz33JSMD3PBiwOv7sWFGdiPu4R9/2Sw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","README.md","LICENSE","package.json"],"_shasum":"d12676787ac17f8e9cfb71febb0d12a492dcb889","gitHead":"45da493e9823a8ae648536e953b606511dc22251","scripts":{"test":"scripts/test","compile":"babel -d lib/ src/","test:cov":"scripts/test-cov","prepublish":"npm run compile"},"_npmUser":{"name":"faassen","email":"faassen@startifact.com"},"repository":{"url":"git+https://github.com/faassen/reselect.git","type":"git"},"_npmVersion":"2.13.1","description":"Selectors for Redux Flux.","directories":{},"_nodeVersion":"0.12.0","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","isparta":"^3.0.3","babel-core":"^5.6.15"}},"1.0.0-alpha":{"name":"reselect","version":"1.0.0-alpha","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@1.0.0-alpha","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"}],"homepage":"https://github.com/faassen/reselect#readme","bugs":{"url":"https://github.com/faassen/reselect/issues"},"dist":{"shasum":"aa95785bc8f3b42844e29b77319361d5cb424290","tarball":"https://registry.npmjs.org/reselect/-/reselect-1.0.0-alpha.tgz","integrity":"sha512-pclB5GmrQB8Xy4G4r7Ye/cwEi1xz6Azj2G8f5Dsk48FAomV0ilj4aobAMiXLARnaYumGkx6VMWEQ6Nz8PBR9sA==","signatures":[{"sig":"MEYCIQCswadyA6OY16ALO620Hq0ZFzhYHU6b8BTKciHPs8+bigIhAKISMuYKapHV81KDWUkv4hDVdsy0U2349Fvrj2cNFgSO","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","README.md","LICENSE","package.json"],"_shasum":"aa95785bc8f3b42844e29b77319361d5cb424290","gitHead":"da70ba712ed93b1aa317ff66df14f3a45cfa306a","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/faassen/reselect.git","type":"git"},"_npmVersion":"2.12.1","description":"Selectors for Redux Flux.","directories":{},"_nodeVersion":"0.12.7","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^0.23","isparta":"^3.0.3","babel-core":"^5.6.15","babel-eslint":"^3.1.15","lodash.memoize":"^3.0.4","eslint-config-airbnb":"0.0.6"}},"1.0.0-alpha2":{"name":"reselect","version":"1.0.0-alpha2","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@1.0.0-alpha2","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"}],"homepage":"https://github.com/faassen/reselect#readme","bugs":{"url":"https://github.com/faassen/reselect/issues"},"dist":{"shasum":"88cf90ff49e301d6dbf9f5e32a7feba854bccb9b","tarball":"https://registry.npmjs.org/reselect/-/reselect-1.0.0-alpha2.tgz","integrity":"sha512-y81xAmcfEn+BVPHd/iiDKzz/oKUzj+3ASREyAZKFeGz1eb38oTmwCg2RYcPBp8+ANuDdCgbcI5K7h+UIluUKjQ==","signatures":[{"sig":"MEUCIGXJHg3sto3PUcI//P/9uOcZTfN7XzM6aJw+CSZIMfftAiEA1rDRN9QHu0PFZPlQo/QgRWqgNXbw90OC4cWi50OPLVk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"88cf90ff49e301d6dbf9f5e32a7feba854bccb9b","gitHead":"22aa8251a2ed37cbf7d00c7aa63420ae64d85ba7","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/faassen/reselect.git","type":"git"},"_npmVersion":"2.12.1","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"0.12.7","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^0.23","isparta":"^3.0.3","babel-core":"^5.6.15","babel-eslint":"^3.1.15","lodash.memoize":"^3.0.4","eslint-config-airbnb":"0.0.6"}},"1.0.0":{"name":"reselect","version":"1.0.0","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@1.0.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"}],"homepage":"https://github.com/faassen/reselect#readme","bugs":{"url":"https://github.com/faassen/reselect/issues"},"dist":{"shasum":"39f35a6158ea9fc591c21c89b48ad7de582ad8da","tarball":"https://registry.npmjs.org/reselect/-/reselect-1.0.0.tgz","integrity":"sha512-su7yGhXd833A0y5gfj81mfSTdvB19TXhdAy9NIiM3tPywCJQ+olw6wIm0iovfaEoEQLH2SIU5QyUatiN9c97vg==","signatures":[{"sig":"MEUCIGftnAv0jzlgGyqpgWNcOnp8nB4bJGVrzO/BsdQ3iMH0AiEAqCC44R8UuK6SLtEkzz3FrMvS6EJUf9k7NyPLhouss/c=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"39f35a6158ea9fc591c21c89b48ad7de582ad8da","gitHead":"c57ed5287f4646bd9580ffca365e8e9cecf1c81b","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/faassen/reselect.git","type":"git"},"_npmVersion":"2.12.1","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"0.12.7","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^0.23","isparta":"^3.0.3","babel-core":"^5.6.15","babel-eslint":"^3.1.15","lodash.memoize":"^3.0.4","eslint-config-airbnb":"0.0.6"}},"1.1.0":{"name":"reselect","version":"1.1.0","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@1.1.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"}],"homepage":"https://github.com/faassen/reselect#readme","bugs":{"url":"https://github.com/faassen/reselect/issues"},"dist":{"shasum":"8d0ea3a9483ae62b1a0d7d8b4355db4d2ed163fb","tarball":"https://registry.npmjs.org/reselect/-/reselect-1.1.0.tgz","integrity":"sha512-yzvtF7bA+OQ01k1Yk7w+kAr++3VLgCgQ4yjpIWiKT+29GoaEhSeGnlfiZdL0Y+ORrIg4ys59nsc8mP0LnbbQmQ==","signatures":[{"sig":"MEQCIAGki3K7gpg447XwQhzJ0Q2egLry5sberc2QsJz52mlnAiA4c2SkxKMhXCUSWI2sld9uaOVPJ+uwwme2VRDHDOPd8Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"8d0ea3a9483ae62b1a0d7d8b4355db4d2ed163fb","gitHead":"401f09c888546d4282edc7aae36ef881f393f5a7","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/faassen/reselect.git","type":"git"},"_npmVersion":"2.14.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"0.12.7","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^0.23","isparta":"^3.0.3","babel-core":"^5.6.15","babel-eslint":"^3.1.15","lodash.memoize":"^3.0.4","eslint-config-airbnb":"0.0.6"}},"2.0.0":{"name":"reselect","version":"2.0.0","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@2.0.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"},{"name":"C. T. Lin"},{"name":"SpainTrain"}],"homepage":"https://github.com/faassen/reselect#readme","bugs":{"url":"https://github.com/faassen/reselect/issues"},"dist":{"shasum":"0f892558b5160b12ee48eb9fe4039e6ba2fe97ab","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.0.0.tgz","integrity":"sha512-DQmkNalvf7lw+gqFOswB0xmbGMnQk/JYdBn2/JAxW0gS3b+xA3cAfgj4+K9ek1Aar6/WNxriwY9m54m7vI2MmA==","signatures":[{"sig":"MEUCIAa3TQqC+wQttHNCASMRdMZf4UfKxVl7qRQ8OYvmUog0AiEA/zaFE8M9YPDesOGD9Q1+lZ2TeY1HbP9we19TUw1vU0Q=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"0f892558b5160b12ee48eb9fe4039e6ba2fe97ab","gitHead":"ee9fff5c012e9e18bd28a15421d140c408524533","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/faassen/reselect.git","type":"git"},"_npmVersion":"2.11.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"0.12.7","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","babel-core":"^5.6.15","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-plugin-react":"^3.5.1","eslint-config-airbnb":"0.1.0"}},"2.0.1":{"name":"reselect","version":"2.0.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.0.1","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"},{"name":"C. T. Lin"},{"name":"SpainTrain"},{"name":"Mark Dalgleish"},{"name":"Brian Ng"}],"homepage":"https://github.com/rackt/reselect#readme","bugs":{"url":"https://github.com/rackt/reselect/issues"},"dist":{"shasum":"20ec075a26fead8dfe26ecfc3a60f7b4818888cf","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.0.1.tgz","integrity":"sha512-sMJZ3E6y9t79ZxhOrrgoYL1ETvtx0tB7F0JbSLnik5bvOG/z4tAA4Hye4gL72ZtWBdMHjk1d+0MWwNq62AYmjw==","signatures":[{"sig":"MEUCIHgvle1sX4lay/8W2ht/qrmbeaRNgnAUeJS+RAB8tnCeAiEAq6a7rABOOyKIFFwJvT6ivkg2g7BDBWMqUtaY0cEX8bc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"20ec075a26fead8dfe26ecfc3a60f7b4818888cf","authors":["Martijn Faassen (https://github.com/faassen)","Lee Bannard (https://github.com/ellbee)","Robert Binna (https://github.com/speedskater)","Philip Spitzlinger (https://github.com/PSpSynedra)"],"gitHead":"e9c0d651a47758e7a720a9359d399ba3ac97cd2b","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/rackt/reselect.git","type":"git"},"_npmVersion":"3.3.9","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.0.0","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"}},"2.0.2":{"name":"reselect","version":"2.0.2","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@2.0.2","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"},{"name":"C. T. Lin"},{"name":"SpainTrain"},{"name":"Mark Dalgleish"},{"name":"Brian Ng"}],"homepage":"https://github.com/rackt/reselect#readme","bugs":{"url":"https://github.com/rackt/reselect/issues"},"dist":{"shasum":"ffad198d3fe94708d9925047967ff5a801828d96","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.0.2.tgz","integrity":"sha512-M9Lx70d1nIcj34AH9Yu1kNkZxNLSCRWd5X5pL3V1iCoLt23QeeWck5fZGupdxgYxYCzf1GZj16roYKNpwkjuTQ==","signatures":[{"sig":"MEUCIH6tT2MSFLHaKT6o0WBsIuk9e6otyRX/KrQZh1v1ohuTAiEA5Ci3TJqdIHRJWaIkNrfrOmYaYo53MxHC4Ew2mnfezzQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"ffad198d3fe94708d9925047967ff5a801828d96","gitHead":"e3a0a36458ec68821c306f5b854abffc7047810c","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel --loose es6.modules -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/rackt/reselect.git","type":"git"},"_npmVersion":"3.3.12","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.3.0","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"}},"2.0.3":{"name":"reselect","version":"2.0.3","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@2.0.3","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"},{"name":"C. T. Lin"},{"name":"SpainTrain"},{"name":"Mark Dalgleish"},{"name":"Brian Ng"}],"homepage":"https://github.com/rackt/reselect#readme","bugs":{"url":"https://github.com/rackt/reselect/issues"},"dist":{"shasum":"cab04c867cf67381dcbe86f3be3caa1831b89259","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.0.3.tgz","integrity":"sha512-DekWFWOjvaqx2s9IRUkp5nscvYG5d1BkQKpItVZHYjjSQTMuxFRSZcjJpKyAkcxl13/feA5z4WV3k5/QnyIuxQ==","signatures":[{"sig":"MEQCIH5T7th3sZVPOCFz90L8QLobFoUwZG/Dv7Yv0c67LE6kAiA4EeXjIrifO0wKlUTOVVn7ttpy3Bhd37SGzLy/KXDucw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"cab04c867cf67381dcbe86f3be3caa1831b89259","gitHead":"244ba5b908e04d94308fcba2e6513c3bf5cb10c3","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel --loose es6.modules -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/rackt/reselect.git","type":"git"},"_npmVersion":"3.5.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.5.0","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.0.3.tgz_1454358228465_0.7160679153166711","host":"packages-8-eu.internal.npmjs.com"}},"2.1.0":{"name":"reselect","version":"2.1.0","keywords":["react","redux"],"author":{"name":"Martijn Faassen"},"license":"MIT","_id":"reselect@2.1.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Martijn Faassen"},{"name":"Lee Bannard"},{"name":"Robert Binna"},{"name":"Philip Spitzlinger"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"},{"name":"C. T. Lin"},{"name":"SpainTrain"},{"name":"Mark Dalgleish"},{"name":"Brian Ng"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"9aac892206bc6e4e276ad7ef259d7b90a9397519","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.1.0.tgz","integrity":"sha512-+jEVo+raYw6gFqgY2W1MX/151w9Y57tMi8Mnpd4ci7OlatastzITDnBs9pRnF9l9Y2S8XBNbMp9cU/d80WHTpw==","signatures":[{"sig":"MEYCIQDTv63j+RjIivs6vYmX2PI+OoQXNsF1SHscmZxzE/zo3QIhAICPGr6KCELwT2HFKrxN3SBMkkk1DgIJ2usQNbi7HYac","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"9aac892206bc6e4e276ad7ef259d7b90a9397519","gitHead":"8a3933d19d1360159a5bb29f46b357dd5c0882b4","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel --loose es6.modules -d lib/ src/","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.6.0","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.6.0","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.1.0.tgz_1457035408458_0.038595605408772826","host":"packages-12-west.internal.npmjs.com"}},"2.2.0":{"name":"reselect","version":"2.2.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.2.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Lee Bannard"},{"name":"Martijn Faassen"},{"name":"Robert Binna"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"},{"name":"Philip Spitzlinger"},{"name":"C. T. Lin"},{"name":"SpainTrain"},{"name":"Mark Dalgleish"},{"name":"Brian Ng"},{"name":"长天之云"},{"name":"Michael Lancaster"},{"name":"Elliot Crosby-McCullough"},{"name":"Max Goodman"},{"name":"Simen Bekkhus"},{"name":"Wade Peterson"},{"name":"chungchiehlun"},{"name":"Dave Hendler"},{"name":"Leon Aves"},{"name":"Ian Ker-Seymer"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"eacdbdeef090f8a5541e3cf8670da23508a5f531","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.2.0.tgz","integrity":"sha512-ECHoIa0SCaHu71LP4sFr44zjs4N+m2xKALso0Jlm8HPZ24opR8u6pLGy1rEZopcRM+q6/yxfltqcGWvESzkRmQ==","signatures":[{"sig":"MEUCIGbZggfiCg7ztgFEa+r8YtCkJVWTYxkLXMIyveojKf/GAiEA1VripQmL9BqubKi9Xz5N/bjMNKsvB9MmK5Ro90i8jgM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"eacdbdeef090f8a5541e3cf8670da23508a5f531","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"36106250f3f54d5f67eb12a2f423ece1dbf7b73c","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel --loose es6.modules -d lib/ src/ && cp ./src/reselect.d.ts lib","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.6.0","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.6.0","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.2.0.tgz_1458014808849_0.048914857441559434","host":"packages-13-west.internal.npmjs.com"}},"2.2.1":{"name":"reselect","version":"2.2.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.2.1","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"name":"Lee Bannard"},{"name":"Martijn Faassen"},{"name":"Robert Binna"},{"name":"Alex Guerra"},{"name":"ryanatkn"},{"name":"Adam Royle"},{"name":"Christian Schuhmann"},{"name":"Jason Huang"},{"name":"Daniel Barreto"},{"name":"Mihail Diordiev"},{"name":"Daniela Borges"},{"name":"Philip Spitzlinger"},{"name":"C. T. Lin"},{"name":"SpainTrain"},{"name":"Mark Dalgleish"},{"name":"Brian Ng"},{"name":"长天之云"},{"name":"Michael Lancaster"},{"name":"Elliot Crosby-McCullough"},{"name":"Max Goodman"},{"name":"Simen Bekkhus"},{"name":"Wade Peterson"},{"name":"chungchiehlun"},{"name":"Dave Hendler"},{"name":"Leon Aves"},{"name":"Ian Ker-Seymer"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"743842708e33e370fb02415824d341ede18b9549","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.2.1.tgz","integrity":"sha512-Pl6DQIfWY2mDc3JRYV5pdbwa9Zg0TQXTmtqPT8ReJqhcF6KOXk0c13NXtBfMhUgonBOffDYeugKmnapKtJtxCA==","signatures":[{"sig":"MEYCIQCNdHyDj/XiNQmqsRHmtqpb8pMbC1Pz3Wd3u5PYPcYlOQIhAPsxXD6+GURM0dOzcdldsC9qMlo0zsC4s7gux6Gy/v49","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"743842708e33e370fb02415824d341ede18b9549","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"240c69464cf87b67d5b6ce6c117f9e57a9e4d086","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel --loose es6.modules -d lib/ src/ && cp ./src/reselect.d.ts lib","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.6.0","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.6.0","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.2.1.tgz_1458016244328_0.48663081717677414","host":"packages-12-west.internal.npmjs.com"}},"2.3.0":{"name":"reselect","version":"2.3.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.3.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"88c0d0f33b0c987e51fe1d39ad81900250997123","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.3.0.tgz","integrity":"sha512-BPbDTxVBSLtc1J6u/uJ+55ZVTUSg7tz20BsPPH/VWe0imkR3Agzbry2nSUqYTbW84XBozFNMFEK977qi7WCsrg==","signatures":[{"sig":"MEUCIQCSb+B5BhbyhrgdWahFMjbidT6OjWYoG6LzFSOXm3YAlQIgAyry6uUV2c5VLO4KyZB8zWRB+SoanoumC9e+CPfWd1I=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","README.md","LICENSE","package.json"],"_shasum":"88c0d0f33b0c987e51fe1d39ad81900250997123","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"8c796c639b1169bee7a860f3f8a9fd314309f379","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel --loose es6.modules -d lib/ src/ && cp ./src/reselect.d.ts lib","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.7.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.9.1","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.3.0.tgz_1460051730917_0.7612621581647545","host":"packages-12-west.internal.npmjs.com"}},"2.4.0":{"name":"reselect","version":"2.4.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.4.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"44d543ea7603f6494be7278ce4ac531649f709d6","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.4.0.tgz","integrity":"sha512-yB/vBJb2FTrQiRphfpbYeBHvDFuNasK5dhMtVLGUvOmejPYA0gv/BC46DabmZVU7OgzSqCnEBzXu7lS3uXheoA==","signatures":[{"sig":"MEQCIF4Upwdz3Ry1PlSzvy9P+rp+Du3RgYcxcfL7i+MwahawAiAiS3O+eZDw7uMPflFpscpbMG6vFMrs/2fTZV8yO2tPzA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","README.md","LICENSE","package.json"],"_shasum":"44d543ea7603f6494be7278ce4ac531649f709d6","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"c7acc62bb6d177a454bde09abf829d361e643c7f","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel/register --recursive","compile":"babel --loose es6.modules -d lib/ src/ && cp ./src/reselect.d.ts lib","test:cov":"babel-node ./node_modules/.bin/isparta cover ./node_modules/.bin/_mocha -- --recursive","prepublish":"npm run compile && npm run compile:umd","compile:umd":"mkdir -p dist/ && babel --loose es6.modules --modules umd --module-id Reselect -o dist/reselect.js src/"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.8.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"src/index.js","_nodeVersion":"5.10.1","devDependencies":{"chai":"^3.0.0","babel":"^5.5.8","mocha":"^2.2.5","eslint":"^1.5","isparta":"^3.0.3","coveralls":"^2.11.4","babel-core":"^5.6.15","codecov.io":"^0.1.6","babel-eslint":"^4.1.3","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.4.0.tgz_1460845584173_0.519965604878962","host":"packages-16-east.internal.npmjs.com"}},"2.5.0":{"name":"reselect","version":"2.5.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.5.0","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"60534aa4eaa35d96da5376b03b4d554b3601490b","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.5.0.tgz","integrity":"sha512-3vKwLdNDoCIgy+EOuUJZ7IOBdVg5XodLYDvM1EFRrOH/WkkXI0yWsY3lmHzKBoHPUGpO82yQWfmrHAp7kN8GCA==","signatures":[{"sig":"MEUCIQDYAcoVfDQgSghIgUSEx8FwtTNVwEpZUD6TCEPDMH704QIgWd3lIzsiG4WxnLNDg/RrHxGjalOBk2f2ZBgBrlDysAo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist"],"_shasum":"60534aa4eaa35d96da5376b03b4d554b3601490b","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"51d7af9805bc1ecf3f20a258f5285a795f4ff632","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel-register --recursive","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"NODE_ENV=test nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"mkdir -p dist/ && NODE_ENV=umd babel -o dist/reselect.js src/","compile:commonjs":"NODE_ENV=commonjs babel -d lib/ src/ && cp ./src/reselect.d.ts lib"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.8.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"5.10.1","devDependencies":{"nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^1.5","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","babel-eslint":"^5.0.4","babel-register":"^6.7.2","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.5.0.tgz_1461241393246_0.11551031307317317","host":"packages-12-west.internal.npmjs.com"}},"2.5.1":{"name":"reselect","version":"2.5.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.5.1","maintainers":[{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"dddb8ea92c79b4e624fd2349f13d28b37d34c70d","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.5.1.tgz","integrity":"sha512-rW2RaSZ6qh9/Sg2JhV+rYxYB3wDXG6jI1RRYlLK4ddOT0kBkG6NOECBxps1KYMcw+NVbdX3mLixPL6EZdp/SFQ==","signatures":[{"sig":"MEQCIC/tM5PQI4hykR7cffYmUKURobccN3Fg4yy3kF8GxoUvAiBpQoj77USKFrVwTkrj4w9I6Adjly5WC77r6pYWM0Y0gg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"dddb8ea92c79b4e624fd2349f13d28b37d34c70d","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"87e9e193322c85f3cd88ab84c231ddac42a96afb","scripts":{"lint":"eslint src test","test":"NODE_ENV=test mocha --compilers js:babel-register --recursive","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"NODE_ENV=test nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"mkdir -p dist/ && NODE_ENV=umd babel -o dist/reselect.js src/","compile:commonjs":"NODE_ENV=commonjs babel -d lib/ src/ && cp ./src/reselect.d.ts lib"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.8.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"5.10.1","devDependencies":{"nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^1.5","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","babel-eslint":"^5.0.4","babel-register":"^6.7.2","lodash.memoize":"^3.0.4","eslint-config-rackt":"1.0.0","eslint-plugin-react":"^3.5.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.5.1.tgz_1461243690980_0.7822486085351557","host":"packages-16-east.internal.npmjs.com"}},"2.5.2":{"name":"reselect","version":"2.5.2","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.5.2","maintainers":[{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"129d6174ff86cc167945938becb54d05f4d32566","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.5.2.tgz","integrity":"sha512-789km8u6zfgj4s4nvCKB/xBft2efZ5H8LtCmzx9Bl+wjxam/S2Rs6KCdCW4F1Nwk521+G5cN6gD7hDi0qKsUDA==","signatures":[{"sig":"MEUCICbPzVwxvazWRSbu0eO48gv5j4CbgFrSWjH9smQTGg0uAiEA74FQBRgYGi8PFi3uwBfz7SXnGPne98SYP/UmOWdW3fg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"129d6174ff86cc167945938becb54d05f4d32566","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"1e7383b8c8e55a58230bbff4b77ff6b88778bb16","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.9.5","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"6.2.2","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"node ./typescript_test/test.js"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/reselect.d.ts lib"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^1.8.10","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.5.2.tgz_1467556287737_0.031201114878058434","host":"packages-12-west.internal.npmjs.com"}},"2.5.3":{"name":"reselect","version":"2.5.3","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.5.3","maintainers":[{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"236591136ad5ff63ee50cdd84feff7f6afd80eea","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.5.3.tgz","integrity":"sha512-rUw39rVqi/+jpWzrqp2Aeie8PNilgjjmHkHzHfFcEAfi/BvdSf8ZHa/DGEKTgUN53YhBflEhCibaKLuTa8xFyw==","signatures":[{"sig":"MEUCIQDCQY2pJL4sseYJ3IHN/v3doR5uR1j84LQRzg4AyS3G0QIgES9vYkQxk6yvKlwlTjGGIzIymwQ8UGOEq4SS9eIcluY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"236591136ad5ff63ee50cdd84feff7f6afd80eea","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"707d3bc23f62aaac099583b539ebb7bb7e61455a","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.9.5","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"6.2.2","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"node ./typescript_test/test.js"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/reselect.d.ts lib"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^1.8.10","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.5.3.tgz_1467630583289_0.6573845301754773","host":"packages-12-west.internal.npmjs.com"}},"2.5.4":{"name":"reselect","version":"2.5.4","keywords":["react","redux"],"license":"MIT","_id":"reselect@2.5.4","maintainers":[{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"b7d23fdf00b83fa7ad0279546f8dbbbd765c7047","tarball":"https://registry.npmjs.org/reselect/-/reselect-2.5.4.tgz","integrity":"sha512-KjVKPrNEDQ4nDuIFseuoNP3yp2lz8bipFlCjUkbD8WZTt2zTcJIfCDaSdOkGrChu9nKfWeXsljQQ2j4I5pcwaQ==","signatures":[{"sig":"MEYCIQDUZMTyBZneAjDKnZ9XV/dgUeT72qfB3sddshz4lm7pAQIhAPGCbZrV8RHqoVqaTTxpzMknedALNXgpfstkwhbTYO4Q","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"b7d23fdf00b83fa7ad0279546f8dbbbd765c7047","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"260e3cbab8fa1a71dfefc026edba447ad5ff3a51","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.10.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"6.4.0","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"node ./typescript_test/test.js"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/reselect.d.ts lib"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^1.8.10","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-2.5.4.tgz_1474104460986_0.24306288827210665","host":"packages-12-west.internal.npmjs.com"}},"3.0.0-rc1":{"name":"reselect","version":"3.0.0-rc1","keywords":["react","redux"],"license":"MIT","_id":"reselect@3.0.0-rc1","maintainers":[{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"7836f10a697ba2be2262a4b281644b359aaccafe","tarball":"https://registry.npmjs.org/reselect/-/reselect-3.0.0-rc1.tgz","integrity":"sha512-E+610Ad6g4daPwg3MgwLJ7tR9YqD5g8QuY+CA/QbG5bidj0yesGC7vdn87QZ+/kBZiTzvVDZWO1BxvLf+kKNUA==","signatures":[{"sig":"MEUCIG2Htu0GgAkclRY85K23n61drf8rKDu2vgLdRIRA0lLyAiEAwx94Zzp/K+uIb644quhmcX5hzsG91uJpxBei2z0aoGc=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"7836f10a697ba2be2262a4b281644b359aaccafe","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"93c0baed080cb5b76f492686c17f0c51480d5818","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"src/reselect.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"4.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"7.6.0","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"node ./typescript_test/test.js"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/reselect.d.ts lib"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^1.8.10","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-3.0.0-rc1.tgz_1489601762260_0.6235726040322334","host":"packages-18-east.internal.npmjs.com"}},"3.0.0-beta.1":{"name":"reselect","version":"3.0.0-beta.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@3.0.0-beta.1","maintainers":[{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"ddbd0343b40a882ff62d99c579c75aa70d51d94a","tarball":"https://registry.npmjs.org/reselect/-/reselect-3.0.0-beta.1.tgz","integrity":"sha512-4j4rdEJw64dX0Aog16saQZkHECpkgerpS11xlUmBUtgVudQMvKdzXjuSgw5k7HN3ZWZSx+av2tWOPcVyT9Nklw==","signatures":[{"sig":"MEYCIQDIlH7J32fSdUw6Qa3FQpkC3AQGXx6N3Z3CgPJb1j3VlAIhAIug1jZu+7VvFRlOImKRzrxfBdOMZK/M9X7muH6ebJet","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"ddbd0343b40a882ff62d99c579c75aa70d51d94a","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"26dc4e97b89754126d931d007a3d1878682063d4","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"lib/index.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"4.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"7.6.0","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"typings-tester --dir typescript_test"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/index.d.ts ./lib/index.d.ts"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^2.1.4","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","typings-tester":"^0.2.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-3.0.0-beta.1.tgz_1489602753256_0.0604798283893615","host":"packages-18-east.internal.npmjs.com"}},"3.0.0-rc":{"name":"reselect","version":"3.0.0-rc","keywords":["react","redux"],"license":"MIT","_id":"reselect@3.0.0-rc","maintainers":[{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"57506046225f58a4a4f3091313035fe2b20c66b7","tarball":"https://registry.npmjs.org/reselect/-/reselect-3.0.0-rc.tgz","integrity":"sha512-ztYxuGeEQWUoosEfRjF2ujlp7uAipa8LrD+QKYSp5lqutP5Od4/j5ZN8j4GocVz+bRUYq7wuOeuteMZ6x6MQUw==","signatures":[{"sig":"MEQCIB2rgUo5VICQvzQKzV35Xx0pPbqU1Sby2Br2zMI5IrhjAiBj1tQ8dmH4HI3IQ7kTENifiXr8z28EwXmlXmmHlrzS/g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"57506046225f58a4a4f3091313035fe2b20c66b7","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"28b3f9970a2d2267bc0354e37c4c904ba24fa4ef","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"lib/index.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"4.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"7.6.0","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"typings-tester --dir typescript_test"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/index.d.ts ./lib/index.d.ts"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^2.1.4","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","typings-tester":"^0.2.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-3.0.0-rc.tgz_1489602864403_0.04839535569772124","host":"packages-12-west.internal.npmjs.com"}},"3.0.0":{"name":"reselect","version":"3.0.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@3.0.0","maintainers":[{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"b2e35977f03048700028eaee3a8c0639e40e8f35","tarball":"https://registry.npmjs.org/reselect/-/reselect-3.0.0.tgz","integrity":"sha512-H4NuTagjmcwEVDH2ME8ffyqiRTxMgmqR4JdKNaqrZryl+1r8jDLz/cZtXv9LP4LmxjHCVy6/NY20+rSm1AVtjg==","signatures":[{"sig":"MEYCIQDNHbuSl/Hg0/dqmYgVYEKdke1r7wbI2ebwXJgLW4gk1QIhAPMxlfk6Gc9eMb11JExdsLK4kwPi14yYDUhM/OVDsVWG","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"b2e35977f03048700028eaee3a8c0639e40e8f35","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"48e22889a3e185427387ff1da8e838591671effb","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"lib/index.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"4.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"7.6.0","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"typings-tester --dir typescript_test"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/index.d.ts ./lib/index.d.ts"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^2.1.4","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","typings-tester":"^0.2.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-3.0.0.tgz_1490387425064_0.016411135205999017","host":"packages-12-west.internal.npmjs.com"}},"3.0.1":{"name":"reselect","version":"3.0.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@3.0.1","maintainers":[{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reactjs/reselect#readme","bugs":{"url":"https://github.com/reactjs/reselect/issues"},"dist":{"shasum":"efdaa98ea7451324d092b2b2163a6a1d7a9a2147","tarball":"https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz","integrity":"sha512-b/6tFZCmRhtBMa4xGqiiRp9jh9Aqi2A687Lo265cN0/QohJQEBPiQ52f4QB6i0eF3yp3hmLL21LSGBcML2dlxA==","signatures":[{"sig":"MEUCICjEd2tqerEDm2u+dx68gwz2GwViCgc/VxtPuKS9IaDCAiEA7X+qz4JVwMb1S4JQ6MrGrbq0/5jeow4ED6U8rofW29U=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"lib/index.js","_from":".","files":["lib","src","dist","es"],"_shasum":"efdaa98ea7451324d092b2b2163a6a1d7a9a2147","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"a46f6629d7884b5b0865fc87b9bb27893295b9f8","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"lib/index.d.ts","_npmUser":{"name":"alex3165","email":"alexr.3165@gmail.com"},"repository":{"url":"git+https://github.com/reactjs/reselect.git","type":"git"},"_npmVersion":"3.10.3","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"6.5.0","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"typings-tester --dir typescript_test"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/index.d.ts ./lib/index.d.ts"}},"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","codecov.io":"^0.1.6","typescript":"^2.1.4","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","typings-tester":"^0.2.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect-3.0.1.tgz_1494453024878_0.7030437828507274","host":"packages-12-west.internal.npmjs.com"}},"4.0.0-beta.1":{"name":"reselect","version":"4.0.0-beta.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.0.0-beta.1","maintainers":[{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"f080c55027e87c6e3861325ff720246d9c1e0880","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.0.0-beta.1.tgz","fileCount":11,"integrity":"sha512-BfQMHuIRbz4FxtxQ1MfjAVLFTeISvysQuO2YcWf92/FKh/ZJvmWkQMY9oCbKyDi26VE6c1CWh3MqMmk58EiVww==","signatures":[{"sig":"MEUCIDVOtO5HC1weCza6tN/AFOV2KSUVKxPGK/xD7IOSKfkzAiEAxAYEYZV2IBR4dmeAzxGT2u0nM0t8kFBBDowVv/wlKRY=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":171502,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbNS68CRA9TVsSAnZWagAAtd0P/2GGt6nXgxYdo/5ZZ5jY\nfkPHJFkl192tAj8eQprFT89HO6zBGwMsZZAXpZwXoyetGIxloFjn0niNzNPq\nn7TB8rYUfuGHQz++EMmGSzCN17jDfsaWa+EGeGgyKuRY+H3MGNTobZAd3ran\npN5VE/VzgPKuUTydmFyeDlJTxiZ7D6YghVRxAcdjYt8XFqtb8z4AbkKWIEyr\na6gnw7qyeFp2Qe5VzNKOEEU3wPfYBQqk3JTsnV3LPODeY/6ThN+g3CGiPfSS\nwP5MNdFB4Y40fzCh0N9ucUYds4lFW3EAyjVHPLmJBakBsmhDAVNWRu5P19cq\nsoD1XaYzBYMsJVyUNqbfHip4xBqQaitVQGmTWrzANXBTFha+K5KRd0Svx2HO\n1gjNPwL9mNTDezJdPgRC/QAJ0JQScFIY36sGX/sZa6rL9AsqjNyUW4qCkHoA\nw/7FeG/KCYBVyhwODUMuG7/ndp1unPiLDuy+MDLWmZRTIU/0NoHDQXO4Iwhs\n3KIW++dJMICnkWfdW/Gy1CzH0Exwv/Xbj6UXdPvV5eLEqPKPRb1M4ncOLXTm\nIZpmQGyqFM2Twk1M01ij7RuM3+pNwcNvHJmcJGwkUP9L2DwQdWHUNz1Mugvf\nQwHVdC0Az7x6TBzgei+EX2N6eTrwq4AIERchWHyrNkjkf3UeJZUwoDmAgD3p\nsTLF\r\n=pMsB\r\n-----END PGP SIGNATURE-----\r\n"},"main":"lib/index.js","files":["lib","src","dist","es"],"module":"es/index.js","readme":"# Reselect\n[![Travis][build-badge]][build]\n[![npm package][npm-badge]][npm]\n[![Coveralls][coveralls-badge]][coveralls]\n\nSimple “selector” library for Redux (and others) inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\n\n* Selectors can compute derived data, allowing Redux to store the minimal possible state.\n* Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\n* Selectors are composable. They can be used as input to other selectors.\n\nYou can play around with the following **example** in [this codepen](https://codepen.io/Domiii/pen/LzGNWj?editors=0010):\n\n```js\nimport { createSelector } from 'reselect'\n\nconst shopItemsSelector = state => state.shop.items\nconst taxPercentSelector = state => state.shop.taxPercent\n\nconst subtotalSelector = createSelector(\n  shopItemsSelector,\n  items => items.reduce((acc, item) => acc + item.value, 0)\n)\n\nconst taxSelector = createSelector(\n  subtotalSelector,\n  taxPercentSelector,\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\n)\n\nexport const totalSelector = createSelector(\n  subtotalSelector,\n  taxSelector,\n  (subtotal, tax) => ({ total: subtotal + tax })\n)\n\nlet exampleState = {\n  shop: {\n    taxPercent: 8,\n    items: [\n      { name: 'apple', value: 1.20 },\n      { name: 'orange', value: 0.95 },\n    ]\n  }\n}\n\nconsole.log(subtotalSelector(exampleState)) // 2.15\nconsole.log(taxSelector(exampleState))      // 0.172\nconsole.log(totalSelector(exampleState))    // { total: 2.322 }\n```\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Example](#example)\n  - [Motivation for Memoized Selectors](#motivation-for-memoized-selectors)\n  - [Creating a Memoized Selector](#creating-a-memoized-selector)\n  - [Composing Selectors](#composing-selectors)\n  - [Connecting a Selector to the Redux Store](#connecting-a-selector-to-the-redux-store)\n  - [Accessing React Props in Selectors](#accessing-react-props-in-selectors)\n  - [Sharing Selectors with Props Across Multiple Component Instances](#sharing-selectors-with-props-across-multiple-component-instances)\n- [API](#api)\n  - [`createSelector`](#createselectorinputselectors--inputselectors-resultfunc)\n  - [`defaultMemoize`](#defaultmemoizefunc-equalitycheck--defaultequalitycheck)\n  - [`createSelectorCreator`](#createselectorcreatormemoize-memoizeoptions)\n  - [`createStructuredSelector`](#createstructuredselectorinputselectors-selectorcreator--createselector)\n- [FAQ](#faq)\n  - [Why isn't my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\n  - [Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\n  - [Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\n  - [The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\n  - [How do I test a selector?](#q-how-do-i-test-a-selector)\n  - [How do I create a selector that takes an argument? ](#q-how-do-i-create-a-selector-that-takes-an-argument)\n  - [How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\n  - [Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\n  - [Are there TypeScript typings?](#q-are-there-typescript-typings)\n  - [How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\n\n- [Related Projects](#related-projects)\n- [License](#license)\n\n## Installation\n    npm install reselect\n\n## Example\n\nIf you prefer a video tutorial, you can find one [here](https://www.youtube.com/watch?v=6Xwo5mVxDqI).\n\n### Motivation for Memoized Selectors\n\n> The examples in this section are based on the [Redux Todos List example](http://redux.js.org/docs/basics/UsageWithReact.html).\n\n#### `containers/VisibleTodoList.js`\n\n```js\nimport { connect } from 'react-redux'\nimport { toggleTodo } from '../actions'\nimport TodoList from '../components/TodoList'\n\nconst getVisibleTodos = (todos, filter) => {\n  switch (filter) {\n    case 'SHOW_ALL':\n      return todos\n    case 'SHOW_COMPLETED':\n      return todos.filter(t => t.completed)\n    case 'SHOW_ACTIVE':\n      return todos.filter(t => !t.completed)\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    todos: getVisibleTodos(state.todos, state.visibilityFilter)\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n    onTodoClick: (id) => {\n      dispatch(toggleTodo(id))\n    }\n  }\n}\n\nconst VisibleTodoList = connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(TodoList)\n\nexport default VisibleTodoList\n```\n\nIn the above example, `mapStateToProps` calls `getVisibleTodos` to calculate `todos`. This works great, but there is a drawback: `todos` is calculated every time the state tree is updated. If the state tree is large, or the calculation expensive, repeating the calculation on every update may cause performance problems. Reselect can help to avoid these unnecessary recalculations.\n\n### Creating a Memoized Selector\n\nWe would like to replace `getVisibleTodos` with a memoized selector that recalculates `todos` when the value of `state.todos` or `state.visibilityFilter` changes, but not when changes occur in other (unrelated) parts of the state tree.\n\nReselect provides a function `createSelector` for creating memoized selectors. `createSelector` takes an array of input-selectors and a transform function as its arguments. If the Redux state tree is mutated in a way that causes the value of an input-selector to change, the selector will call its transform function with the values of the input-selectors as arguments and return the result. If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.\n\nLet's define a memoized selector named `getVisibleTodos` to replace the non-memoized version above:\n\n#### `selectors/index.js`\n\n```js\nimport { createSelector } from 'reselect'\n\nconst getVisibilityFilter = (state) => state.visibilityFilter\nconst getTodos = (state) => state.todos\n\nexport const getVisibleTodos = createSelector(\n  [ getVisibilityFilter, getTodos ],\n  (visibilityFilter, todos) => {\n    switch (visibilityFilter) {\n      case 'SHOW_ALL':\n        return todos\n      case 'SHOW_COMPLETED':\n        return todos.filter(t => t.completed)\n      case 'SHOW_ACTIVE':\n        return todos.filter(t => !t.completed)\n    }\n  }\n)\n```\n\nIn the example above, `getVisibilityFilter` and `getTodos` are input-selectors. They are created as ordinary non-memoized selector functions because they do not transform the data they select. `getVisibleTodos` on the other hand is a memoized selector. It takes `getVisibilityFilter` and `getTodos` as input-selectors, and a transform function that calculates the filtered todos list.\n\n### Composing Selectors\n\nA memoized selector can itself be an input-selector to another memoized selector. Here is `getVisibleTodos` being used as an input-selector to a selector that further filters the todos by keyword:\n\n```js\nconst getKeyword = (state) => state.keyword\n\nconst getVisibleTodosFilteredByKeyword = createSelector(\n  [ getVisibleTodos, getKeyword ],\n  (visibleTodos, keyword) => visibleTodos.filter(\n    todo => todo.text.includes(keyword)\n  )\n)\n```\n\n### Connecting a Selector to the Redux Store\n\nIf you are using [React Redux](https://github.com/reduxjs/react-redux), you can call selectors as regular functions inside `mapStateToProps()`:\n\n#### `containers/VisibleTodoList.js`\n\n```js\nimport { connect } from 'react-redux'\nimport { toggleTodo } from '../actions'\nimport TodoList from '../components/TodoList'\nimport { getVisibleTodos } from '../selectors'\n\nconst mapStateToProps = (state) => {\n  return {\n    todos: getVisibleTodos(state)\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n    onTodoClick: (id) => {\n      dispatch(toggleTodo(id))\n    }\n  }\n}\n\nconst VisibleTodoList = connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(TodoList)\n\nexport default VisibleTodoList\n```\n\n### Accessing React Props in Selectors\n\n> This section introduces a hypothetical extension to our app that allows it to support multiple Todo Lists. Please note that a full implementation of this extension requires changes to the reducers, components, actions etc. that aren’t directly relevant to the topics discussed and have been omitted for brevity.\n\nSo far we have only seen selectors receive the Redux store state as an argument, but a selector can receive props too.\n\nHere is an `App` component that renders three `VisibleTodoList` component instances, each of which has a `listId` prop:\n\n#### `components/App.js`\n\n```js\nimport React from 'react'\nimport Footer from './Footer'\nimport AddTodo from '../containers/AddTodo'\nimport VisibleTodoList from '../containers/VisibleTodoList'\n\nconst App = () => (\n  <div>\n    <VisibleTodoList listId=\"1\" />\n    <VisibleTodoList listId=\"2\" />\n    <VisibleTodoList listId=\"3\" />\n  </div>\n)\n```\n\nEach `VisibleTodoList` container should select a different slice of the state depending on the value of the `listId` prop, so let’s modify `getVisibilityFilter` and `getTodos` to accept a props argument:\n\n#### `selectors/todoSelectors.js`\n\n```js\nimport { createSelector } from 'reselect'\n\nconst getVisibilityFilter = (state, props) =>\n  state.todoLists[props.listId].visibilityFilter\n\nconst getTodos = (state, props) =>\n  state.todoLists[props.listId].todos\n\nconst getVisibleTodos = createSelector(\n  [ getVisibilityFilter, getTodos ],\n  (visibilityFilter, todos) => {\n    switch (visibilityFilter) {\n      case 'SHOW_COMPLETED':\n        return todos.filter(todo => todo.completed)\n      case 'SHOW_ACTIVE':\n        return todos.filter(todo => !todo.completed)\n      default:\n        return todos\n    }\n  }\n)\n\nexport default getVisibleTodos\n```\n\n`props` can be passed to `getVisibleTodos` from `mapStateToProps`:\n\n```js\nconst mapStateToProps = (state, props) => {\n  return {\n    todos: getVisibleTodos(state, props)\n  }\n}\n```\n\nSo now `getVisibleTodos` has access to `props`, and everything seems to be working fine.\n\n**But there is a problem!**\n\nUsing the `getVisibleTodos` selector with multiple instances of the `VisibleTodoList` container will not correctly memoize:\n\n#### `containers/VisibleTodoList.js`\n\n```js\nimport { connect } from 'react-redux'\nimport { toggleTodo } from '../actions'\nimport TodoList from '../components/TodoList'\nimport { getVisibleTodos } from '../selectors'\n\nconst mapStateToProps = (state, props) => {\n  return {\n    // WARNING: THE FOLLOWING SELECTOR DOES NOT CORRECTLY MEMOIZE\n    todos: getVisibleTodos(state, props)\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n    onTodoClick: (id) => {\n      dispatch(toggleTodo(id))\n    }\n  }\n}\n\nconst VisibleTodoList = connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(TodoList)\n\nexport default VisibleTodoList\n```\n\nA selector created with `createSelector` has a cache size of 1 and only returns the cached value when its set of arguments is the same as its previous set of arguments. If we alternate between rendering `<VisibleTodoList listId=\"1\" />` and `<VisibleTodoList listId=\"2\" />`, the shared selector will alternate between receiving `{listId: 1}` and `{listId: 2}` as its `props` argument. This will cause the arguments to be different on each call, so the selector will always recompute instead of returning the cached value. We’ll see how to overcome this limitation in the next section.\n\n### Sharing Selectors with Props Across Multiple Component Instances\n\n> The examples in this section require React Redux v4.3.0 or greater\n\n> An alternative approach can be found in [re-reselect](https://github.com/toomuchdesign/re-reselect)\n\nTo share a selector across multiple `VisibleTodoList` instances while passing in `props` **and** retaining memoization, each instance of the component needs its own private copy of the selector.\n\nLet’s create a function named `makeGetVisibleTodos` that returns a new copy of the `getVisibleTodos` selector each time it is called:\n\n#### `selectors/todoSelectors.js`\n\n```js\nimport { createSelector } from 'reselect'\n\nconst getVisibilityFilter = (state, props) =>\n  state.todoLists[props.listId].visibilityFilter\n\nconst getTodos = (state, props) =>\n  state.todoLists[props.listId].todos\n\nconst makeGetVisibleTodos = () => {\n  return createSelector(\n    [ getVisibilityFilter, getTodos ],\n    (visibilityFilter, todos) => {\n      switch (visibilityFilter) {\n        case 'SHOW_COMPLETED':\n          return todos.filter(todo => todo.completed)\n        case 'SHOW_ACTIVE':\n          return todos.filter(todo => !todo.completed)\n        default:\n          return todos\n      }\n    }\n  )\n}\n\nexport default makeGetVisibleTodos\n```\n\nWe also need a way to give each instance of a container access to its own private selector. The `mapStateToProps` argument of `connect` can help with this.\n\n**If the `mapStateToProps` argument supplied to `connect` returns a function instead of an object, it will be used to create an individual `mapStateToProps` function for each instance of the container.**\n\nIn the example below `makeMapStateToProps` creates a new `getVisibleTodos` selector, and returns a `mapStateToProps` function that has exclusive access to the new selector:\n\n```js\nconst makeMapStateToProps = () => {\n  const getVisibleTodos = makeGetVisibleTodos()\n  const mapStateToProps = (state, props) => {\n    return {\n      todos: getVisibleTodos(state, props)\n    }\n  }\n  return mapStateToProps\n}\n```\n\nIf we pass `makeMapStateToProps` to `connect`, each instance of the `VisibleTodoList` container will get its own `mapStateToProps` function with a private `getVisibleTodos` selector. Memoization will now work correctly regardless of the render order of the `VisibleTodoList` containers.\n\n#### `containers/VisibleTodoList.js`\n\n```js\nimport { connect } from 'react-redux'\nimport { toggleTodo } from '../actions'\nimport TodoList from '../components/TodoList'\nimport { makeGetVisibleTodos } from '../selectors'\n\nconst makeMapStateToProps = () => {\n  const getVisibleTodos = makeGetVisibleTodos()\n  const mapStateToProps = (state, props) => {\n    return {\n      todos: getVisibleTodos(state, props)\n    }\n  }\n  return mapStateToProps\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n    onTodoClick: (id) => {\n      dispatch(toggleTodo(id))\n    }\n  }\n}\n\nconst VisibleTodoList = connect(\n  makeMapStateToProps,\n  mapDispatchToProps\n)(TodoList)\n\nexport default VisibleTodoList\n```\n\n## API\n\n### createSelector(...inputSelectors | [inputSelectors], resultFunc)\n\nTakes one or more selectors, or an array of selectors, computes their values and passes them as arguments to `resultFunc`.\n\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\n\nSelectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector.\n\n```js\nconst mySelector = createSelector(\n  state => state.values.value1,\n  state => state.values.value2,\n  (value1, value2) => value1 + value2\n)\n\n// You can also pass an array of selectors\nconst totalSelector = createSelector(\n  [\n    state => state.values.value1,\n    state => state.values.value2\n  ],\n  (value1, value2) => value1 + value2\n)\n```\n\nIt can be useful to access the props of a component from within a selector. When a selector is connected to a component with `connect`, the component props are passed as the second argument to the selector:\n\n```js\nconst abSelector = (state, props) => state.a * props.b\n\n// props only (ignoring state argument)\nconst cSelector =  (_, props) => props.c\n\n// state only (props argument omitted as not required)\nconst dSelector = state => state.d\n\nconst totalSelector = createSelector(\n  abSelector,\n  cSelector,\n  dSelector,\n  (ab, c, d) => ({\n    total: ab + c + d\n  })\n)\n\n```\n\n### defaultMemoize(func, equalityCheck = defaultEqualityCheck)\n\n`defaultMemoize` memoizes the function passed in the func parameter. It is the memoize function used by `createSelector`.\n\n`defaultMemoize` has a cache size of 1. This means it always recalculates when the value of an argument changes.\n\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\n\n```js\nfunction defaultEqualityCheck(currentVal, previousVal) {\n  return currentVal === previousVal\n}\n```\n\n`defaultMemoize` can be used with `createSelectorCreator` to [customize the `equalityCheck` function](#customize-equalitycheck-for-defaultmemoize).\n\n### createSelectorCreator(memoize, ...memoizeOptions)\n\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\n\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\n\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\n\n```js\nconst customSelectorCreator = createSelectorCreator(\n  customMemoize, // function to be used to memoize resultFunc\n  option1, // option1 will be passed as second argument to customMemoize\n  option2, // option2 will be passed as third argument to customMemoize\n  option3 // option3 will be passed as fourth argument to customMemoize\n)\n\nconst customSelector = customSelectorCreator(\n  input1,\n  input2,\n  resultFunc // resultFunc will be passed as first argument to customMemoize\n)\n```\n\nInternally `customSelector` calls the memoize function as follows:\n\n```js\ncustomMemoize(resultFunc, option1, option2, option3)\n```\n\nHere are some examples of how you might use `createSelectorCreator`:\n\n#### Customize `equalityCheck` for `defaultMemoize`\n\n```js\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\nimport isEqual from 'lodash.isEqual'\n\n// create a \"selector creator\" that uses lodash.isEqual instead of ===\nconst createDeepEqualSelector = createSelectorCreator(\n  defaultMemoize,\n  isEqual\n)\n\n// use the new \"selector creator\" to create a selector\nconst mySelector = createDeepEqualSelector(\n  state => state.values.filter(val => val < 5),\n  values => values.reduce((acc, val) => acc + val, 0)\n)\n```\n\n#### Use memoize function from lodash for an unbounded cache\n\n```js\nimport { createSelectorCreator } from 'reselect'\nimport memoize from 'lodash.memoize'\n\nlet called = 0\nconst hashFn = (...args) => args.reduce(\n  (acc, val) => acc + '-' + JSON.stringify(val),\n  ''\n)\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\nconst selector = customSelectorCreator(\n  state => state.a,\n  state => state.b,\n  (a, b) => {\n    called++\n    return a + b\n  }\n)\n```\n\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\n\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\n\n```js\nconst mySelectorA = state => state.a\nconst mySelectorB = state => state.b\n\n// The result function in the following selector\n// is simply building an object from the input selectors\nconst structuredSelector = createSelector(\n   mySelectorA,\n   mySelectorB,\n   mySelectorC,\n   (a, b, c) => ({\n     a,\n     b,\n     c\n   })\n)\n```\n\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\n\n```js\nconst mySelectorA = state => state.a\nconst mySelectorB = state => state.b\n\nconst structuredSelector = createStructuredSelector({\n  x: mySelectorA,\n  y: mySelectorB\n})\n\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\n```\n\nStructured selectors can be nested:\n\n```js\nconst nestedSelector = createStructuredSelector({\n  subA: createStructuredSelector({\n    selectorA,\n    selectorB\n  }),\n  subB: createStructuredSelector({\n    selectorC,\n    selectorD\n  })\n})\n\n```\n\n## FAQ\n\n### Q: Why isn’t my selector recomputing when the input state changes?\n\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\n\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\n\n```js\nconst isFirstTodoCompleteSelector = createSelector(\n  state => state.todos[0],\n  todo => todo && todo.completed\n)\n```\n\nThe following state update function **will not** work with `isFirstTodoCompleteSelector`:\n\n```js\nexport default function todos(state = initialState, action) {\n  switch (action.type) {\n  case COMPLETE_ALL:\n    const areAllMarked = state.every(todo => todo.completed)\n    // BAD: mutating an existing object\n    return state.map(todo => {\n      todo.completed = !areAllMarked\n      return todo\n    })\n\n  default:\n    return state\n  }\n}\n```\n\nThe following state update function **will** work with `isFirstTodoCompleteSelector`:\n\n```js\nexport default function todos(state = initialState, action) {\n  switch (action.type) {\n  case COMPLETE_ALL:\n    const areAllMarked = state.every(todo => todo.completed)\n    // GOOD: returning a new object each time with Object.assign\n    return state.map(todo => Object.assign({}, todo, {\n      completed: !areAllMarked\n    }))\n\n  default:\n    return state\n  }\n}\n```\n\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\n\n### Q: Why is my selector recomputing when the input state stays the same?\n\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\n\n```js\nimport { REMOVE_OLD } from '../constants/ActionTypes'\n\nconst initialState = [\n  {\n    text: 'Use Redux',\n    completed: false,\n    id: 0,\n    timestamp: Date.now()\n  }\n]\n\nexport default function todos(state = initialState, action) {\n  switch (action.type) {\n  case REMOVE_OLD:\n    return state.filter(todo => {\n      return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\n    })\n  default:\n    return state\n  }\n}\n```\n\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\n\n```js\nimport { createSelector } from 'reselect'\n\nconst todosSelector = state => state.todos\n\nexport const visibleTodosSelector = createSelector(\n  todosSelector,\n  (todos) => {\n    ...\n  }\n)\n```\n\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\n\n```js\nimport { REMOVE_OLD } from '../constants/ActionTypes'\nimport isEqual from 'lodash.isEqual'\n\nconst initialState = [\n  {\n    text: 'Use Redux',\n    completed: false,\n    id: 0,\n    timestamp: Date.now()\n  }\n]\n\nexport default function todos(state = initialState, action) {\n  switch (action.type) {\n  case REMOVE_OLD:\n    const updatedState =  state.filter(todo => {\n      return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\n    })\n    return isEqual(updatedState, state) ? state : updatedState\n  default:\n    return state\n  }\n}\n```\n\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\n\n```js\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\nimport isEqual from 'lodash.isEqual'\n\nconst todosSelector = state => state.todos\n\n// create a \"selector creator\" that uses lodash.isEqual instead of ===\nconst createDeepEqualSelector = createSelectorCreator(\n  defaultMemoize,\n  isEqual\n)\n\n// use the new \"selector creator\" to create a selector\nconst mySelector = createDeepEqualSelector(\n  todosSelector,\n  (todos) => {\n    ...\n  }\n)\n```\n\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\n\n### Q: Can I use Reselect without Redux?\n\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It is currently being used successfully in traditional Flux apps.\n\n> If you create selectors using `createSelector` make sure its arguments are immutable.\n> See [here](#createselectorinputselectors--inputselectors-resultfunc)\n\n### Q: How do I create a selector that takes an argument?\n\nA: Keep in mind that selectors can access React props, so if your arguments are (or can be made available as) React props, you can use that functionality. [See here](#accessing-react-props-in-selectors) for details.\n\nOtherwise, Reselect doesn't have built-in support for creating selectors that accepts arguments, but here are some suggestions for implementing similar functionality...\n\nIf the argument is not dynamic you can use a factory function:\n\n```js\nconst expensiveItemSelectorFactory = minValue => {\n  return createSelector(\n    shopItemsSelector,\n    items => items.filter(item => item.value > minValue)\n  )\n}\n\nconst subtotalSelector = createSelector(\n  expensiveItemSelectorFactory(200),\n  items => items.reduce((acc, item) => acc + item.value, 0)\n)\n```\n\nThe general consensus [here](https://github.com/reduxjs/reselect/issues/38) and [over at nuclear-js](https://github.com/optimizely/nuclear-js/issues/14) is that if a selector needs a dynamic argument, then that argument should probably be state in the store. If you decide that you do require a selector with a dynamic argument, then a selector that returns a memoized function may be suitable:\n\n```js\nimport { createSelector } from 'reselect'\nimport memoize from 'lodash.memoize'\n\nconst expensiveSelector = createSelector(\n  state => state.items,\n  items => memoize(\n    minValue => items.filter(item => item.value > minValue)\n  )\n)\n\nconst expensiveFilter = expensiveSelector(state)\n\nconst slightlyExpensive = expensiveFilter(100)\nconst veryExpensive = expensiveFilter(1000000)\n```\n\n### Q: The default memoization function is no good, can I use a different one?\n\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\n\n### Q: How do I test a selector?\n\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\n\n```js\nconst selector = createSelector(\n  state => state.a,\n  state => state.b,\n  (a, b) => ({\n    c: a * 2,\n    d: b * 3\n  })\n)\n\ntest(\"selector unit test\", () => {\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\n})\n```\n\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\n\n```js\nsuite('selector', () => {\n  let state = { a: 1, b: 2 }\n\n  const reducer = (state, action) => (\n    {\n      a: action(state.a),\n      b: action(state.b)\n    }\n  )\n\n  const selector = createSelector(\n    state => state.a,\n    state => state.b,\n    (a, b) => ({\n      c: a * 2,\n      d: b * 3\n    })\n  )\n\n  const plusOne = x => x + 1\n  const id = x => x\n\n  test(\"selector unit test\", () => {\n    state = reducer(state, plusOne)\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\n    state = reducer(state, id)\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\n    assert.equal(selector.recomputations(), 1)\n    state = reducer(state, plusOne)\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\n    assert.equal(selector.recomputations(), 2)\n  })\n})\n```\n\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\n\nFor example if you have a set of selectors like this:\n\n**selectors.js**\n```js\nexport const firstSelector = createSelector( ... )\nexport const secondSelector = createSelector( ... )\nexport const thirdSelector = createSelector( ... )\n\nexport const myComposedSelector = createSelector(\n  firstSelector,\n  secondSelector,\n  thirdSelector,\n  (first, second, third) => first * second < third\n)\n```\n\nAnd then a set of unit tests like this:\n\n**test/selectors.js**\n\n```js\n// tests for the first three selectors...\ntest(\"firstSelector unit test\", () => { ... })\ntest(\"secondSelector unit test\", () => { ... })\ntest(\"thirdSelector unit test\", () => { ... })\n\n// We have already tested the previous\n// three selector outputs so we can just call `.resultFunc`\n// with the values we want to test directly:\ntest(\"myComposedSelector unit test\", () => {\n  // here instead of calling selector()\n  // we just call selector.resultFunc()\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\n})\n```\n\nFinally, each selector has a `resetRecomputations` method that sets\nrecomputations back to 0.  The intended use is for a complex selector that may\nhave many independent tests and you don't want to manually manage the\ncomputation count or create a \"dummy\" selector for each test.\n\n### Q: How do I use Reselect with Immutable.js?\n\nA: Selectors created with `createSelector` should work just fine with Immutable.js data structures.\n\nIf your selector is recomputing and you don't think the state has changed, make sure you are aware of which Immutable.js update methods **always** return a new object and which update methods only return a new object **when the collection actually changes**.\n\n```js\nimport Immutable from 'immutable'\n\nlet myMap = Immutable.Map({\n  a: 1,\n  b: 2,\n  c: 3\n})\n\n // set, merge and others only return a new obj when update changes collection\nlet newMap = myMap.set('a', 1)\nassert.equal(myMap, newMap)\nnewMap = myMap.merge({ 'a': 1 })\nassert.equal(myMap, newMap)\n// map, reduce, filter and others always return a new obj\nnewMap = myMap.map(a => a * 1)\nassert.notEqual(myMap, newMap)\n```\n\nIf a selector's input is updated by an operation that always returns a new object, it may be performing unnecessary recomputations. See [here](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same) for a discussion on the pros and cons of using a deep equality check like `Immutable.is` to eliminate unnecessary recomputations.\n\n### Q: Can I share a selector across multiple component instances?\n\nA: Selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\n\n* Create a factory function which returns a new selector for each instance of the component. There is built-in support for factory functions in React Redux v4.3 or higher. See [here](#sharing-selectors-with-props-across-multiple-component-instances) for an example.\n\n* Create a custom selector with a cache size greater than one.\n\n### Q: Are there TypeScript Typings?\n\nA: Yes! They are included and referenced in `package.json`. They should Just Work™.\n\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\n\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\n\n## Related Projects\n\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\n\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\n\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\n\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\n\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\n\n* Measure selector recomputations across the app and identify performance bottlenecks\n* Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\n* Statically export a JSON representation of your selector graph for further analysis\n\n### [reselect-map](https://github.com/HeyImAlex/reselect-map)\n\nCan be useful when doing **very expensive** computations on elements of a collection because Reselect might not give you the granularity of caching that you need. Check out the reselect-maps README for examples.\n\n**The optimizations in reselect-map only apply in a small number of cases. If you are unsure whether you need it, you don't!**\n\n## License\n\nMIT\n\n[build-badge]: https://img.shields.io/travis/reduxjs/reselect/master.svg?style=flat-square\n[build]: https://travis-ci.org/reduxjs/reselect\n\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\n[npm]: https://www.npmjs.org/package/reselect\n\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"3932567f7ca88d8dface5b46b0d2e0f23bd8ae07","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:umdmin && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","compile:umdmin":"uglifyjs dist/reselect.js -mt -o dist/reselect.min.js","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"lib/index.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.1.0","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"9.11.1","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"typings-tester --dir typescript_test"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/index.d.ts ./lib/index.d.ts"}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","uglify-js":"^3.0.20","codecov.io":"^0.1.6","typescript":"^2.9.2","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","typings-tester":"^0.2.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.0.0-beta.1_1530212028193_0.49600884525912026","host":"s3://npm-registry-packages"}},"4.0.0":{"name":"reselect","version":"4.0.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.0.0","maintainers":[{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"threehams","email":"threehams@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"f2529830e5d3d0e021408b246a206ef4ea4437f7","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz","fileCount":11,"integrity":"sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==","signatures":[{"sig":"MEYCIQC9J1ORmRcyL+l8iuDrWU8QUMlECUHcLmbuh8+ePykmPgIhANwSxi2iSBf3rCx4lSCHulvTgYT1gJ/ZYTJqDfr6UZRK","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":171495,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbsLXlCRA9TVsSAnZWagAAfUoP/1fY2YsQ5KgSbBL4TniU\nw+iHK98yXHJ1BNfwKiCrN69PLPdhkcabmyQ2BqPgBt2XXC7oWwBr9gO4Ac0g\nQhDY4ghAEjXwjGn+8p4OcqXRHmFNbGBBE5HWGIlMRAIfKDldQIaQX6VvFYzN\nWraWiBNd5KyJ0lYVxifOHyplG6iiT8sxbVDY3qOxF96kv+DEha8H7o8kV0UF\nTq8OtqT0nlHbWzPjDqATIYAHV6x8hFqQo2D2eAsMmjZKCSFFU8MHdqfJxwgQ\n8iG0bz8+/pOKdaHr95MzJRmlBfETMn1rZXINMeeLm2YemKo0mMVMap2Gbk3y\naeKw7P81Zm+rZwq5whgjrb/8aAc7L1nzxpHFuMa3525Txukt1aL1pNxpNXFM\nFzV5bV/Af0yZfudoBjQ6ce/umFni5DUyGAbiRLwft4j+AMJoU7B6vwLfFLGZ\nNyXXvJwYNdL6j0ET84Mdktyq0vDSxDFuB/2mwQifqcSNGanF7mmx4zj+TXzb\nmvr3soVLKRVr09zQTT1EPAmHoYMp2S+3llCgG52T9jN1A62eb1qev8qPlBHl\nQ2w6OG9BGmRfKNbRyNSNOH4t3dbBHJk/wgwEZbED1rUYGjuVVeSMUX7b1FMo\nh6+VllPLPFdZFzcSxGgOngkjJ1xLdYDdM7NROiGyAeA4Rp9R5UcwpXG+EVse\nxX1I\r\n=/V6n\r\n-----END PGP SIGNATURE-----\r\n"},"main":"lib/index.js","module":"es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"1f3fdeb22c3fef1b4a212f16b814b5fd9fdf07a9","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:umdmin && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"better-npm-run compile:umd","compile:umdmin":"uglifyjs dist/reselect.js -mt -o dist/reselect.min.js","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"lib/index.d.ts","_npmUser":{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.4.1","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"9.11.1","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:babel-register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:babel-register --ui tdd"},"compile:umd":{"env":{"NODE_ENV":"umd"},"command":"mkdirp dist/ && babel -o dist/reselect.js src/"},"test:typescript":{"command":"typings-tester --dir typescript_test"},"compile:commonjs":{"env":{"NODE_ENV":"commonjs"},"command":"babel -d lib/ src/ && ncp ./src/index.d.ts ./lib/index.d.ts"}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","babel-cli":"^6.7.5","coveralls":"^2.11.4","uglify-js":"^3.0.20","codecov.io":"^0.1.6","typescript":"^2.9.2","babel-register":"^6.7.2","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","typings-tester":"^0.2.0","eslint-plugin-react":"^5.1.1","babel-plugin-check-es2015-constants":"^6.7.2","babel-plugin-transform-es2015-spread":"^6.6.5","babel-plugin-transform-es2015-parameters":"^6.7.0","babel-plugin-transform-es2015-modules-umd":"^6.6.5","babel-plugin-transform-es2015-block-scoping":"^6.7.1","babel-plugin-transform-es2015-function-name":"^6.5.0","babel-plugin-transform-es2015-arrow-functions":"^6.5.2","babel-plugin-transform-es2015-modules-commonjs":"^6.7.4","babel-plugin-transform-es2015-template-literals":"^6.6.5","babel-plugin-transform-es2015-shorthand-properties":"^6.5.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.0.0_1538307556892_0.09388397927391567","host":"s3://npm-registry-packages"}},"4.1.0-alpha.0":{"name":"reselect","version":"4.1.0-alpha.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.0-alpha.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"6edec8f2858c24b31a0c8dfb1d4724f5bb0550d7","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.0-alpha.0.tgz","fileCount":12,"integrity":"sha512-uSJIR3jJ6anfN0+LpK5t3buS6x+VOekEXl/9iVZZBhSNvet1jON29qz3ClNteE/fhDFEHCwzPErVzDTVS73ABg==","signatures":[{"sig":"MEYCIQDtN3iTmeXvHBborBuQotPNW8TBUyf+hkIYv+/96+dgVwIhALSINirpktPeqHrtC0zVGT48EZePrwx/P4BO+RS1lX8a","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":129603},"main":"lib/index.js","module":"es/index.js","readme":"# Reselect\r\n[![Travis][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\nSimple “selector” library for Redux (and others) inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n* Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n* Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n* Selectors are composable. They can be used as input to other selectors.\r\n\r\nYou can play around with the following **example** in [this codepen](https://codepen.io/Domiii/pen/LzGNWj?editors=0010):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst shopItemsSelector = state => state.shop.items\r\nconst taxPercentSelector = state => state.shop.taxPercent\r\n\r\nconst subtotalSelector = createSelector(\r\n  shopItemsSelector,\r\n  items => items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst taxSelector = createSelector(\r\n  subtotalSelector,\r\n  taxPercentSelector,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst totalSelector = createSelector(\r\n  subtotalSelector,\r\n  taxSelector,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.20 },\r\n      { name: 'orange', value: 0.95 },\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(subtotalSelector(exampleState)) // 2.15\r\nconsole.log(taxSelector(exampleState))      // 0.172\r\nconsole.log(totalSelector(exampleState))    // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n- [Example](#example)\r\n  - [Motivation for Memoized Selectors](#motivation-for-memoized-selectors)\r\n  - [Creating a Memoized Selector](#creating-a-memoized-selector)\r\n  - [Composing Selectors](#composing-selectors)\r\n  - [Connecting a Selector to the Redux Store](#connecting-a-selector-to-the-redux-store)\r\n  - [Accessing React Props in Selectors](#accessing-react-props-in-selectors)\r\n  - [Sharing Selectors with Props Across Multiple Component Instances](#sharing-selectors-with-props-across-multiple-component-instances)\r\n- [API](#api)\r\n  - [`createSelector`](#createselectorinputselectors--inputselectors-resultfunc)\r\n  - [`defaultMemoize`](#defaultmemoizefunc-equalitycheck--defaultequalitycheck)\r\n  - [`createSelectorCreator`](#createselectorcreatormemoize-memoizeoptions)\r\n  - [`createStructuredSelector`](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [FAQ](#faq)\r\n  - [Why isn't my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [How do I create a selector that takes an argument? ](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n  - [Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript typings?](#q-are-there-typescript-typings)\r\n  - [How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n\r\n## Installation\r\n    npm install reselect\r\n\r\n## Example\r\n\r\nIf you prefer a video tutorial, you can find one [here](https://www.youtube.com/watch?v=6Xwo5mVxDqI).\r\n\r\n### Motivation for Memoized Selectors\r\n\r\n> The examples in this section are based on the [Redux Todos List example](https://redux.js.org/recipes/computing-derived-data/).\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\n\r\nconst getVisibleTodos = (todos, filter) => {\r\n  switch (filter) {\r\n    case 'SHOW_ALL':\r\n      return todos\r\n    case 'SHOW_COMPLETED':\r\n      return todos.filter(t => t.completed)\r\n    case 'SHOW_ACTIVE':\r\n      return todos.filter(t => !t.completed)\r\n  }\r\n}\r\n\r\nconst mapStateToProps = (state) => {\r\n  return {\r\n    todos: getVisibleTodos(state.todos, state.visibilityFilter)\r\n  }\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\nIn the above example, `mapStateToProps` calls `getVisibleTodos` to calculate `todos`. This works great, but there is a drawback: `todos` is calculated every time the state tree is updated. If the state tree is large, or the calculation expensive, repeating the calculation on every update may cause performance problems. Reselect can help to avoid these unnecessary recalculations.\r\n\r\n### Creating a Memoized Selector\r\n\r\nWe would like to replace `getVisibleTodos` with a memoized selector that recalculates `todos` when the value of `state.todos` or `state.visibilityFilter` changes, but not when changes occur in other (unrelated) parts of the state tree.\r\n\r\nReselect provides a function `createSelector` for creating memoized selectors. `createSelector` takes an array of input-selectors and a transform function as its arguments. If the Redux state tree is mutated in a way that causes the value of an input-selector to change, the selector will call its transform function with the values of the input-selectors as arguments and return the result. If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.\r\n\r\nLet's define a memoized selector named `getVisibleTodos` to replace the non-memoized version above:\r\n\r\n#### `selectors/index.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst getVisibilityFilter = (state) => state.visibilityFilter\r\nconst getTodos = (state) => state.todos\r\n\r\nexport const getVisibleTodos = createSelector(\r\n  [ getVisibilityFilter, getTodos ],\r\n  (visibilityFilter, todos) => {\r\n    switch (visibilityFilter) {\r\n      case 'SHOW_ALL':\r\n        return todos\r\n      case 'SHOW_COMPLETED':\r\n        return todos.filter(t => t.completed)\r\n      case 'SHOW_ACTIVE':\r\n        return todos.filter(t => !t.completed)\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIn the example above, `getVisibilityFilter` and `getTodos` are input-selectors. They are created as ordinary non-memoized selector functions because they do not transform the data they select. `getVisibleTodos` on the other hand is a memoized selector. It takes `getVisibilityFilter` and `getTodos` as input-selectors, and a transform function that calculates the filtered todos list.\r\n\r\n### Composing Selectors\r\n\r\nA memoized selector can itself be an input-selector to another memoized selector. Here is `getVisibleTodos` being used as an input-selector to a selector that further filters the todos by keyword:\r\n\r\n```js\r\nconst getKeyword = (state) => state.keyword\r\n\r\nconst getVisibleTodosFilteredByKeyword = createSelector(\r\n  [ getVisibleTodos, getKeyword ],\r\n  (visibleTodos, keyword) => visibleTodos.filter(\r\n    todo => todo.text.includes(keyword)\r\n  )\r\n)\r\n```\r\n\r\n### Connecting a Selector to the Redux Store\r\n\r\nIf you are using [React Redux](https://github.com/reduxjs/react-redux), you can call selectors as regular functions inside `mapStateToProps()`:\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { getVisibleTodos } from '../selectors'\r\n\r\nconst mapStateToProps = (state) => {\r\n  return {\r\n    todos: getVisibleTodos(state)\r\n  }\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\n### Accessing React Props in Selectors\r\n\r\n> This section introduces a hypothetical extension to our app that allows it to support multiple Todo Lists. Please note that a full implementation of this extension requires changes to the reducers, components, actions etc. that aren’t directly relevant to the topics discussed and have been omitted for brevity.\r\n\r\nSo far we have only seen selectors receive the Redux store state as an argument, but a selector can receive props too.\r\n\r\nHere is an `App` component that renders three `VisibleTodoList` component instances, each of which has a `listId` prop:\r\n\r\n#### `components/App.js`\r\n\r\n```js\r\nimport React from 'react'\r\nimport Footer from './Footer'\r\nimport AddTodo from '../containers/AddTodo'\r\nimport VisibleTodoList from '../containers/VisibleTodoList'\r\n\r\nconst App = () => (\r\n  <div>\r\n    <VisibleTodoList listId=\"1\" />\r\n    <VisibleTodoList listId=\"2\" />\r\n    <VisibleTodoList listId=\"3\" />\r\n  </div>\r\n)\r\n```\r\n\r\nEach `VisibleTodoList` container should select a different slice of the state depending on the value of the `listId` prop, so let’s modify `getVisibilityFilter` and `getTodos` to accept a props argument:\r\n\r\n#### `selectors/todoSelectors.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst getVisibilityFilter = (state, props) =>\r\n  state.todoLists[props.listId].visibilityFilter\r\n\r\nconst getTodos = (state, props) =>\r\n  state.todoLists[props.listId].todos\r\n\r\nconst getVisibleTodos = createSelector(\r\n  [ getVisibilityFilter, getTodos ],\r\n  (visibilityFilter, todos) => {\r\n    switch (visibilityFilter) {\r\n      case 'SHOW_COMPLETED':\r\n        return todos.filter(todo => todo.completed)\r\n      case 'SHOW_ACTIVE':\r\n        return todos.filter(todo => !todo.completed)\r\n      default:\r\n        return todos\r\n    }\r\n  }\r\n)\r\n\r\nexport default getVisibleTodos\r\n```\r\n\r\n`props` can be passed to `getVisibleTodos` from `mapStateToProps`:\r\n\r\n```js\r\nconst mapStateToProps = (state, props) => {\r\n  return {\r\n    todos: getVisibleTodos(state, props)\r\n  }\r\n}\r\n```\r\n\r\nSo now `getVisibleTodos` has access to `props`, and everything seems to be working fine.\r\n\r\n**But there is a problem!**\r\n\r\nUsing the `getVisibleTodos` selector with multiple instances of the `VisibleTodoList` container will not correctly memoize:\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { getVisibleTodos } from '../selectors'\r\n\r\nconst mapStateToProps = (state, props) => {\r\n  return {\r\n    // WARNING: THE FOLLOWING SELECTOR DOES NOT CORRECTLY MEMOIZE\r\n    todos: getVisibleTodos(state, props)\r\n  }\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\nA selector created with `createSelector` has a cache size of 1 and only returns the cached value when its set of arguments is the same as its previous set of arguments. If we alternate between rendering `<VisibleTodoList listId=\"1\" />` and `<VisibleTodoList listId=\"2\" />`, the shared selector will alternate between receiving `{listId: 1}` and `{listId: 2}` as its `props` argument. This will cause the arguments to be different on each call, so the selector will always recompute instead of returning the cached value. We’ll see how to overcome this limitation in the next section.\r\n\r\n### Sharing Selectors with Props Across Multiple Component Instances\r\n\r\n> The examples in this section require React Redux v4.3.0 or greater\r\n\r\n> An alternative approach can be found in [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nTo share a selector across multiple `VisibleTodoList` instances while passing in `props` **and** retaining memoization, each instance of the component needs its own private copy of the selector.\r\n\r\nLet’s create a function named `makeGetVisibleTodos` that returns a new copy of the `getVisibleTodos` selector each time it is called:\r\n\r\n#### `selectors/todoSelectors.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst getVisibilityFilter = (state, props) =>\r\n  state.todoLists[props.listId].visibilityFilter\r\n\r\nconst getTodos = (state, props) =>\r\n  state.todoLists[props.listId].todos\r\n\r\nconst makeGetVisibleTodos = () => {\r\n  return createSelector(\r\n    [ getVisibilityFilter, getTodos ],\r\n    (visibilityFilter, todos) => {\r\n      switch (visibilityFilter) {\r\n        case 'SHOW_COMPLETED':\r\n          return todos.filter(todo => todo.completed)\r\n        case 'SHOW_ACTIVE':\r\n          return todos.filter(todo => !todo.completed)\r\n        default:\r\n          return todos\r\n      }\r\n    }\r\n  )\r\n}\r\n\r\nexport default makeGetVisibleTodos\r\n```\r\n\r\nWe also need a way to give each instance of a container access to its own private selector. The `mapStateToProps` argument of `connect` can help with this.\r\n\r\n**If the `mapStateToProps` argument supplied to `connect` returns a function instead of an object, it will be used to create an individual `mapStateToProps` function for each instance of the container.**\r\n\r\nIn the example below `makeMapStateToProps` creates a new `getVisibleTodos` selector, and returns a `mapStateToProps` function that has exclusive access to the new selector:\r\n\r\n```js\r\nconst makeMapStateToProps = () => {\r\n  const getVisibleTodos = makeGetVisibleTodos()\r\n  const mapStateToProps = (state, props) => {\r\n    return {\r\n      todos: getVisibleTodos(state, props)\r\n    }\r\n  }\r\n  return mapStateToProps\r\n}\r\n```\r\n\r\nIf we pass `makeMapStateToProps` to `connect`, each instance of the `VisibleTodoList` container will get its own `mapStateToProps` function with a private `getVisibleTodos` selector. Memoization will now work correctly regardless of the render order of the `VisibleTodoList` containers.\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { makeGetVisibleTodos } from '../selectors'\r\n\r\nconst makeMapStateToProps = () => {\r\n  const getVisibleTodos = makeGetVisibleTodos()\r\n  const mapStateToProps = (state, props) => {\r\n    return {\r\n      todos: getVisibleTodos(state, props)\r\n    }\r\n  }\r\n  return mapStateToProps\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  makeMapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc)\r\n\r\nTakes one or more selectors, or an array of selectors, computes their values and passes them as arguments to `resultFunc`.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nSelectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector.\r\n\r\n```js\r\nconst mySelector = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst totalSelector = createSelector(\r\n  [\r\n    state => state.values.value1,\r\n    state => state.values.value2\r\n  ],\r\n  (value1, value2) => value1 + value2\r\n)\r\n```\r\n\r\nIt can be useful to access the props of a component from within a selector. When a selector is connected to a component with `connect`, the component props are passed as the second argument to the selector:\r\n\r\n```js\r\nconst abSelector = (state, props) => state.a * props.b\r\n\r\n// props only (ignoring state argument)\r\nconst cSelector =  (_, props) => props.c\r\n\r\n// state only (props argument omitted as not required)\r\nconst dSelector = state => state.d\r\n\r\nconst totalSelector = createSelector(\r\n  abSelector,\r\n  cSelector,\r\n  dSelector,\r\n  (ab, c, d) => ({\r\n    total: ab + c + d\r\n  })\r\n)\r\n\r\n```\r\n\r\n### defaultMemoize(func, equalityCheck = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a cache size of 1. This means it always recalculates when the value of an argument changes.\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\n`defaultMemoize` can be used with `createSelectorCreator` to [customize the `equalityCheck` function](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) => args.reduce(\r\n  (acc, val) => acc + '-' + JSON.stringify(val),\r\n  ''\r\n)\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst mySelectorA = state => state.a\r\nconst mySelectorB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(\r\n   mySelectorA,\r\n   mySelectorB,\r\n   (a, b) => ({\r\n     a,\r\n     b\r\n   })\r\n)\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst mySelectorA = state => state.a\r\nconst mySelectorB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: mySelectorA,\r\n  y: mySelectorB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst isFirstTodoCompleteSelector = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `isFirstTodoCompleteSelector`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case COMPLETE_ALL:\r\n    const areAllMarked = state.every(todo => todo.completed)\r\n    // BAD: mutating an existing object\r\n    return state.map(todo => {\r\n      todo.completed = !areAllMarked\r\n      return todo\r\n    })\r\n\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `isFirstTodoCompleteSelector`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case COMPLETE_ALL:\r\n    const areAllMarked = state.every(todo => todo.completed)\r\n    // GOOD: returning a new object each time with Object.assign\r\n    return state.map(todo => Object.assign({}, todo, {\r\n      completed: !areAllMarked\r\n    }))\r\n\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case REMOVE_OLD:\r\n    return state.filter(todo => {\r\n      return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n    })\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const visibleTodosSelector = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case REMOVE_OLD:\r\n    const updatedState =  state.filter(todo => {\r\n      return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n    })\r\n    return isEqual(updatedState, state) ? state : updatedState\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It is currently being used successfully in traditional Flux apps.\r\n\r\n> If you create selectors using `createSelector` make sure its arguments are immutable.\r\n> See [here](#createselectorinputselectors--inputselectors-resultfunc)\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nA: Keep in mind that selectors can access React props, so if your arguments are (or can be made available as) React props, you can use that functionality. [See here](#accessing-react-props-in-selectors) for details.\r\n\r\nOtherwise, Reselect doesn't have built-in support for creating selectors that accepts arguments, but here are some suggestions for implementing similar functionality...\r\n\r\nIf the argument is not dynamic you can use a factory function:\r\n\r\n```js\r\nconst expensiveItemSelectorFactory = minValue => {\r\n  return createSelector(\r\n    shopItemsSelector,\r\n    items => items.filter(item => item.value > minValue)\r\n  )\r\n}\r\n\r\nconst subtotalSelector = createSelector(\r\n  expensiveItemSelectorFactory(200),\r\n  items => items.reduce((acc, item) => acc + item.value, 0)\r\n)\r\n```\r\n\r\nThe general consensus [here](https://github.com/reduxjs/reselect/issues/38) and [over at nuclear-js](https://github.com/optimizely/nuclear-js/issues/14) is that if a selector needs a dynamic argument, then that argument should probably be state in the store. If you decide that you do require a selector with a dynamic argument, then a selector that returns a memoized function may be suitable:\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst expensiveSelector = createSelector(\r\n  state => state.items,\r\n  items => memoize(\r\n    minValue => items.filter(item => item.value > minValue)\r\n  )\r\n)\r\n\r\nconst expensiveFilter = expensiveSelector(state)\r\n\r\nconst slightlyExpensive = expensiveFilter(100)\r\nconst veryExpensive = expensiveFilter(1000000)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest(\"selector unit test\", () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => (\r\n    {\r\n      a: action(state.a),\r\n      b: action(state.b)\r\n    }\r\n  )\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test(\"selector unit test\", () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n```js\r\nexport const firstSelector = createSelector( ... )\r\nexport const secondSelector = createSelector( ... )\r\nexport const thirdSelector = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  firstSelector,\r\n  secondSelector,\r\n  thirdSelector,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"firstSelector unit test\", () => { ... })\r\ntest(\"secondSelector unit test\", () => { ... })\r\ntest(\"thirdSelector unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0.  The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: How do I use Reselect with Immutable.js?\r\n\r\nA: Selectors created with `createSelector` should work just fine with Immutable.js data structures.\r\n\r\nIf your selector is recomputing and you don't think the state has changed, make sure you are aware of which Immutable.js update methods **always** return a new object and which update methods only return a new object **when the collection actually changes**.\r\n\r\n```js\r\nimport Immutable from 'immutable'\r\n\r\nlet myMap = Immutable.Map({\r\n  a: 1,\r\n  b: 2,\r\n  c: 3\r\n})\r\n\r\n // set, merge and others only return a new obj when update changes collection\r\nlet newMap = myMap.set('a', 1)\r\nassert.equal(myMap, newMap)\r\nnewMap = myMap.merge({ 'a': 1 })\r\nassert.equal(myMap, newMap)\r\n// map, reduce, filter and others always return a new obj\r\nnewMap = myMap.map(a => a * 1)\r\nassert.notEqual(myMap, newMap)\r\n```\r\n\r\nIf a selector's input is updated by an operation that always returns a new object, it may be performing unnecessary recomputations. See [here](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same) for a discussion on the pros and cons of using a deep equality check like `Immutable.is` to eliminate unnecessary recomputations.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n* Create a factory function which returns a new selector for each instance of the component. There is built-in support for factory functions in React Redux v4.3 or higher. See [here](#sharing-selectors-with-props-across-multiple-component-instances) for an example.\r\n\r\n* Create a custom selector with a cache size greater than one.\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! They are included and referenced in `package.json`. They should Just Work™.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n* Measure selector recomputations across the app and identify performance bottlenecks\r\n* Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n* Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-map](https://github.com/HeyImAlex/reselect-map)\r\n\r\nCan be useful when doing **very expensive** computations on elements of a collection because Reselect might not give you the granularity of caching that you need. Check out the reselect-maps README for examples.\r\n\r\n**The optimizations in reselect-map only apply in a small number of cases. If you are unsure whether you need it, you don't!**\r\n\r\n## License\r\n\r\nMIT\r\n\r\n[build-badge]: https://img.shields.io/travis/reduxjs/reselect/master.svg?style=flat-square\r\n[build]: https://travis-ci.org/reduxjs/reselect\r\n\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"4556d0f93b06def4f8a3f8a4953def30bcec2db5","scripts":{"lint":"eslint src test","test":"better-npm-run test","compile":"npm run compile:commonjs && npm run compile:umd && npm run compile:umdmin && npm run compile:es","test:cov":"better-npm-run test:cov","compile:es":"babel -d es/ src/","prepublish":"npm run compile","compile:umd":"rollup -c","compile:umdmin":"uglifyjs dist/reselect.js -mt -o dist/reselect.min.js","test:typescript":"better-npm-run test:typescript","compile:commonjs":"better-npm-run compile:commonjs"},"typings":"lib/index.d.ts","_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"es/index.js","_nodeVersion":"14.17.0","betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/ && ncp ./src/index.d.ts ./lib/index.d.ts"}},"typesVersions":{"<4.2.0":{"*":["src/typesVersions/ts4.1/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","rollup":"^2.38.5","coveralls":"^2.11.4","uglify-js":"^3.0.20","@babel/cli":"^7.12.13","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.12.13","@types/lodash":"^4.14.175","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","@babel/register":"^7.12.13","@babel/preset-env":"^7.12.13","eslint-plugin-react":"^5.1.1","@rollup/plugin-babel":"^5.2.3"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.0-alpha.0_1634423230642_0.2706696271667379","host":"s3://npm-registry-packages"}},"4.1.0-alpha.1":{"name":"reselect","version":"4.1.0-alpha.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.0-alpha.1","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"48303cf439a3702450d25d8364feea79c0d60ac3","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.0-alpha.1.tgz","fileCount":14,"integrity":"sha512-+9Y88Cov93WZinP4zXk/OBSrWgr32B8UedKP9H9GWp7WOK2GBO2Vp7Dt7zO1tOCety1NiOPPAFNb2dCkWyJVdw==","signatures":[{"sig":"MEYCIQDR/7Er5B704yNhKhe6r1kICNM+z0bmbKwkCzwjK8GpPwIhAPH4fdMbiylA+jfP7lT6jiY115WOSxtc5y6V1i9q2lA2","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":137320},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","readme":"# Reselect\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\nSimple “selector” library for Redux (and others) inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n* Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n* Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n* Selectors are composable. They can be used as input to other selectors.\r\n\r\nYou can play around with the following **example** in [this codepen](https://codepen.io/Domiii/pen/LzGNWj?editors=0010):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst shopItemsSelector = state => state.shop.items\r\nconst taxPercentSelector = state => state.shop.taxPercent\r\n\r\nconst subtotalSelector = createSelector(\r\n  shopItemsSelector,\r\n  items => items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst taxSelector = createSelector(\r\n  subtotalSelector,\r\n  taxPercentSelector,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst totalSelector = createSelector(\r\n  subtotalSelector,\r\n  taxSelector,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.20 },\r\n      { name: 'orange', value: 0.95 },\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(subtotalSelector(exampleState)) // 2.15\r\nconsole.log(taxSelector(exampleState))      // 0.172\r\nconsole.log(totalSelector(exampleState))    // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n- [Example](#example)\r\n  - [Motivation for Memoized Selectors](#motivation-for-memoized-selectors)\r\n  - [Creating a Memoized Selector](#creating-a-memoized-selector)\r\n  - [Composing Selectors](#composing-selectors)\r\n  - [Connecting a Selector to the Redux Store](#connecting-a-selector-to-the-redux-store)\r\n  - [Accessing React Props in Selectors](#accessing-react-props-in-selectors)\r\n  - [Sharing Selectors with Props Across Multiple Component Instances](#sharing-selectors-with-props-across-multiple-component-instances)\r\n- [API](#api)\r\n  - [`createSelector`](#createselectorinputselectors--inputselectors-resultfunc)\r\n  - [`defaultMemoize`](#defaultmemoizefunc-equalitycheck--defaultequalitycheck)\r\n  - [`createSelectorCreator`](#createselectorcreatormemoize-memoizeoptions)\r\n  - [`createStructuredSelector`](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [FAQ](#faq)\r\n  - [Why isn't my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [How do I create a selector that takes an argument? ](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n  - [Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript typings?](#q-are-there-typescript-typings)\r\n  - [How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n\r\n## Installation\r\n    npm install reselect\r\n\r\n## Example\r\n\r\nIf you prefer a video tutorial, you can find one [here](https://www.youtube.com/watch?v=6Xwo5mVxDqI).\r\n\r\n### Motivation for Memoized Selectors\r\n\r\n> The examples in this section are based on the [Redux Todos List example](https://redux.js.org/recipes/computing-derived-data/).\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\n\r\nconst getVisibleTodos = (todos, filter) => {\r\n  switch (filter) {\r\n    case 'SHOW_ALL':\r\n      return todos\r\n    case 'SHOW_COMPLETED':\r\n      return todos.filter(t => t.completed)\r\n    case 'SHOW_ACTIVE':\r\n      return todos.filter(t => !t.completed)\r\n  }\r\n}\r\n\r\nconst mapStateToProps = (state) => {\r\n  return {\r\n    todos: getVisibleTodos(state.todos, state.visibilityFilter)\r\n  }\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\nIn the above example, `mapStateToProps` calls `getVisibleTodos` to calculate `todos`. This works great, but there is a drawback: `todos` is calculated every time the state tree is updated. If the state tree is large, or the calculation expensive, repeating the calculation on every update may cause performance problems. Reselect can help to avoid these unnecessary recalculations.\r\n\r\n### Creating a Memoized Selector\r\n\r\nWe would like to replace `getVisibleTodos` with a memoized selector that recalculates `todos` when the value of `state.todos` or `state.visibilityFilter` changes, but not when changes occur in other (unrelated) parts of the state tree.\r\n\r\nReselect provides a function `createSelector` for creating memoized selectors. `createSelector` takes an array of input-selectors and a transform function as its arguments. If the Redux state tree is mutated in a way that causes the value of an input-selector to change, the selector will call its transform function with the values of the input-selectors as arguments and return the result. If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.\r\n\r\nLet's define a memoized selector named `getVisibleTodos` to replace the non-memoized version above:\r\n\r\n#### `selectors/index.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst getVisibilityFilter = (state) => state.visibilityFilter\r\nconst getTodos = (state) => state.todos\r\n\r\nexport const getVisibleTodos = createSelector(\r\n  [ getVisibilityFilter, getTodos ],\r\n  (visibilityFilter, todos) => {\r\n    switch (visibilityFilter) {\r\n      case 'SHOW_ALL':\r\n        return todos\r\n      case 'SHOW_COMPLETED':\r\n        return todos.filter(t => t.completed)\r\n      case 'SHOW_ACTIVE':\r\n        return todos.filter(t => !t.completed)\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIn the example above, `getVisibilityFilter` and `getTodos` are input-selectors. They are created as ordinary non-memoized selector functions because they do not transform the data they select. `getVisibleTodos` on the other hand is a memoized selector. It takes `getVisibilityFilter` and `getTodos` as input-selectors, and a transform function that calculates the filtered todos list.\r\n\r\n### Composing Selectors\r\n\r\nA memoized selector can itself be an input-selector to another memoized selector. Here is `getVisibleTodos` being used as an input-selector to a selector that further filters the todos by keyword:\r\n\r\n```js\r\nconst getKeyword = (state) => state.keyword\r\n\r\nconst getVisibleTodosFilteredByKeyword = createSelector(\r\n  [ getVisibleTodos, getKeyword ],\r\n  (visibleTodos, keyword) => visibleTodos.filter(\r\n    todo => todo.text.includes(keyword)\r\n  )\r\n)\r\n```\r\n\r\n### Connecting a Selector to the Redux Store\r\n\r\nIf you are using [React Redux](https://github.com/reduxjs/react-redux), you can call selectors as regular functions inside `mapStateToProps()`:\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { getVisibleTodos } from '../selectors'\r\n\r\nconst mapStateToProps = (state) => {\r\n  return {\r\n    todos: getVisibleTodos(state)\r\n  }\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\n### Accessing React Props in Selectors\r\n\r\n> This section introduces a hypothetical extension to our app that allows it to support multiple Todo Lists. Please note that a full implementation of this extension requires changes to the reducers, components, actions etc. that aren’t directly relevant to the topics discussed and have been omitted for brevity.\r\n\r\nSo far we have only seen selectors receive the Redux store state as an argument, but a selector can receive props too.\r\n\r\nHere is an `App` component that renders three `VisibleTodoList` component instances, each of which has a `listId` prop:\r\n\r\n#### `components/App.js`\r\n\r\n```js\r\nimport React from 'react'\r\nimport Footer from './Footer'\r\nimport AddTodo from '../containers/AddTodo'\r\nimport VisibleTodoList from '../containers/VisibleTodoList'\r\n\r\nconst App = () => (\r\n  <div>\r\n    <VisibleTodoList listId=\"1\" />\r\n    <VisibleTodoList listId=\"2\" />\r\n    <VisibleTodoList listId=\"3\" />\r\n  </div>\r\n)\r\n```\r\n\r\nEach `VisibleTodoList` container should select a different slice of the state depending on the value of the `listId` prop, so let’s modify `getVisibilityFilter` and `getTodos` to accept a props argument:\r\n\r\n#### `selectors/todoSelectors.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst getVisibilityFilter = (state, props) =>\r\n  state.todoLists[props.listId].visibilityFilter\r\n\r\nconst getTodos = (state, props) =>\r\n  state.todoLists[props.listId].todos\r\n\r\nconst getVisibleTodos = createSelector(\r\n  [ getVisibilityFilter, getTodos ],\r\n  (visibilityFilter, todos) => {\r\n    switch (visibilityFilter) {\r\n      case 'SHOW_COMPLETED':\r\n        return todos.filter(todo => todo.completed)\r\n      case 'SHOW_ACTIVE':\r\n        return todos.filter(todo => !todo.completed)\r\n      default:\r\n        return todos\r\n    }\r\n  }\r\n)\r\n\r\nexport default getVisibleTodos\r\n```\r\n\r\n`props` can be passed to `getVisibleTodos` from `mapStateToProps`:\r\n\r\n```js\r\nconst mapStateToProps = (state, props) => {\r\n  return {\r\n    todos: getVisibleTodos(state, props)\r\n  }\r\n}\r\n```\r\n\r\nSo now `getVisibleTodos` has access to `props`, and everything seems to be working fine.\r\n\r\n**But there is a problem!**\r\n\r\nUsing the `getVisibleTodos` selector with multiple instances of the `VisibleTodoList` container will not correctly memoize:\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { getVisibleTodos } from '../selectors'\r\n\r\nconst mapStateToProps = (state, props) => {\r\n  return {\r\n    // WARNING: THE FOLLOWING SELECTOR DOES NOT CORRECTLY MEMOIZE\r\n    todos: getVisibleTodos(state, props)\r\n  }\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\nA selector created with `createSelector` has a cache size of 1 and only returns the cached value when its set of arguments is the same as its previous set of arguments. If we alternate between rendering `<VisibleTodoList listId=\"1\" />` and `<VisibleTodoList listId=\"2\" />`, the shared selector will alternate between receiving `{listId: 1}` and `{listId: 2}` as its `props` argument. This will cause the arguments to be different on each call, so the selector will always recompute instead of returning the cached value. We’ll see how to overcome this limitation in the next section.\r\n\r\n### Sharing Selectors with Props Across Multiple Component Instances\r\n\r\n> The examples in this section require React Redux v4.3.0 or greater\r\n\r\n> An alternative approach can be found in [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nTo share a selector across multiple `VisibleTodoList` instances while passing in `props` **and** retaining memoization, each instance of the component needs its own private copy of the selector.\r\n\r\nLet’s create a function named `makeGetVisibleTodos` that returns a new copy of the `getVisibleTodos` selector each time it is called:\r\n\r\n#### `selectors/todoSelectors.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst getVisibilityFilter = (state, props) =>\r\n  state.todoLists[props.listId].visibilityFilter\r\n\r\nconst getTodos = (state, props) =>\r\n  state.todoLists[props.listId].todos\r\n\r\nconst makeGetVisibleTodos = () => {\r\n  return createSelector(\r\n    [ getVisibilityFilter, getTodos ],\r\n    (visibilityFilter, todos) => {\r\n      switch (visibilityFilter) {\r\n        case 'SHOW_COMPLETED':\r\n          return todos.filter(todo => todo.completed)\r\n        case 'SHOW_ACTIVE':\r\n          return todos.filter(todo => !todo.completed)\r\n        default:\r\n          return todos\r\n      }\r\n    }\r\n  )\r\n}\r\n\r\nexport default makeGetVisibleTodos\r\n```\r\n\r\nWe also need a way to give each instance of a container access to its own private selector. The `mapStateToProps` argument of `connect` can help with this.\r\n\r\n**If the `mapStateToProps` argument supplied to `connect` returns a function instead of an object, it will be used to create an individual `mapStateToProps` function for each instance of the container.**\r\n\r\nIn the example below `makeMapStateToProps` creates a new `getVisibleTodos` selector, and returns a `mapStateToProps` function that has exclusive access to the new selector:\r\n\r\n```js\r\nconst makeMapStateToProps = () => {\r\n  const getVisibleTodos = makeGetVisibleTodos()\r\n  const mapStateToProps = (state, props) => {\r\n    return {\r\n      todos: getVisibleTodos(state, props)\r\n    }\r\n  }\r\n  return mapStateToProps\r\n}\r\n```\r\n\r\nIf we pass `makeMapStateToProps` to `connect`, each instance of the `VisibleTodoList` container will get its own `mapStateToProps` function with a private `getVisibleTodos` selector. Memoization will now work correctly regardless of the render order of the `VisibleTodoList` containers.\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { makeGetVisibleTodos } from '../selectors'\r\n\r\nconst makeMapStateToProps = () => {\r\n  const getVisibleTodos = makeGetVisibleTodos()\r\n  const mapStateToProps = (state, props) => {\r\n    return {\r\n      todos: getVisibleTodos(state, props)\r\n    }\r\n  }\r\n  return mapStateToProps\r\n}\r\n\r\nconst mapDispatchToProps = (dispatch) => {\r\n  return {\r\n    onTodoClick: (id) => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  makeMapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc)\r\n\r\nTakes one or more selectors, or an array of selectors, computes their values and passes them as arguments to `resultFunc`.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nSelectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector.\r\n\r\n```js\r\nconst mySelector = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst totalSelector = createSelector(\r\n  [\r\n    state => state.values.value1,\r\n    state => state.values.value2\r\n  ],\r\n  (value1, value2) => value1 + value2\r\n)\r\n```\r\n\r\nIt can be useful to access the props of a component from within a selector. When a selector is connected to a component with `connect`, the component props are passed as the second argument to the selector:\r\n\r\n```js\r\nconst abSelector = (state, props) => state.a * props.b\r\n\r\n// props only (ignoring state argument)\r\nconst cSelector =  (_, props) => props.c\r\n\r\n// state only (props argument omitted as not required)\r\nconst dSelector = state => state.d\r\n\r\nconst totalSelector = createSelector(\r\n  abSelector,\r\n  cSelector,\r\n  dSelector,\r\n  (ab, c, d) => ({\r\n    total: ab + c + d\r\n  })\r\n)\r\n\r\n```\r\n\r\n### defaultMemoize(func, equalityCheck = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a cache size of 1. This means it always recalculates when the value of an argument changes.\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\n`defaultMemoize` can be used with `createSelectorCreator` to [customize the `equalityCheck` function](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) => args.reduce(\r\n  (acc, val) => acc + '-' + JSON.stringify(val),\r\n  ''\r\n)\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst mySelectorA = state => state.a\r\nconst mySelectorB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(\r\n   mySelectorA,\r\n   mySelectorB,\r\n   (a, b) => ({\r\n     a,\r\n     b\r\n   })\r\n)\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst mySelectorA = state => state.a\r\nconst mySelectorB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: mySelectorA,\r\n  y: mySelectorB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst isFirstTodoCompleteSelector = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `isFirstTodoCompleteSelector`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case COMPLETE_ALL:\r\n    const areAllMarked = state.every(todo => todo.completed)\r\n    // BAD: mutating an existing object\r\n    return state.map(todo => {\r\n      todo.completed = !areAllMarked\r\n      return todo\r\n    })\r\n\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `isFirstTodoCompleteSelector`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case COMPLETE_ALL:\r\n    const areAllMarked = state.every(todo => todo.completed)\r\n    // GOOD: returning a new object each time with Object.assign\r\n    return state.map(todo => Object.assign({}, todo, {\r\n      completed: !areAllMarked\r\n    }))\r\n\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case REMOVE_OLD:\r\n    return state.filter(todo => {\r\n      return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n    })\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const visibleTodosSelector = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n  case REMOVE_OLD:\r\n    const updatedState =  state.filter(todo => {\r\n      return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n    })\r\n    return isEqual(updatedState, state) ? state : updatedState\r\n  default:\r\n    return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It is currently being used successfully in traditional Flux apps.\r\n\r\n> If you create selectors using `createSelector` make sure its arguments are immutable.\r\n> See [here](#createselectorinputselectors--inputselectors-resultfunc)\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nA: Keep in mind that selectors can access React props, so if your arguments are (or can be made available as) React props, you can use that functionality. [See here](#accessing-react-props-in-selectors) for details.\r\n\r\nOtherwise, Reselect doesn't have built-in support for creating selectors that accepts arguments, but here are some suggestions for implementing similar functionality...\r\n\r\nIf the argument is not dynamic you can use a factory function:\r\n\r\n```js\r\nconst expensiveItemSelectorFactory = minValue => {\r\n  return createSelector(\r\n    shopItemsSelector,\r\n    items => items.filter(item => item.value > minValue)\r\n  )\r\n}\r\n\r\nconst subtotalSelector = createSelector(\r\n  expensiveItemSelectorFactory(200),\r\n  items => items.reduce((acc, item) => acc + item.value, 0)\r\n)\r\n```\r\n\r\nThe general consensus [here](https://github.com/reduxjs/reselect/issues/38) and [over at nuclear-js](https://github.com/optimizely/nuclear-js/issues/14) is that if a selector needs a dynamic argument, then that argument should probably be state in the store. If you decide that you do require a selector with a dynamic argument, then a selector that returns a memoized function may be suitable:\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst expensiveSelector = createSelector(\r\n  state => state.items,\r\n  items => memoize(\r\n    minValue => items.filter(item => item.value > minValue)\r\n  )\r\n)\r\n\r\nconst expensiveFilter = expensiveSelector(state)\r\n\r\nconst slightlyExpensive = expensiveFilter(100)\r\nconst veryExpensive = expensiveFilter(1000000)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest(\"selector unit test\", () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => (\r\n    {\r\n      a: action(state.a),\r\n      b: action(state.b)\r\n    }\r\n  )\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test(\"selector unit test\", () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n```js\r\nexport const firstSelector = createSelector( ... )\r\nexport const secondSelector = createSelector( ... )\r\nexport const thirdSelector = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  firstSelector,\r\n  secondSelector,\r\n  thirdSelector,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"firstSelector unit test\", () => { ... })\r\ntest(\"secondSelector unit test\", () => { ... })\r\ntest(\"thirdSelector unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0.  The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: How do I use Reselect with Immutable.js?\r\n\r\nA: Selectors created with `createSelector` should work just fine with Immutable.js data structures.\r\n\r\nIf your selector is recomputing and you don't think the state has changed, make sure you are aware of which Immutable.js update methods **always** return a new object and which update methods only return a new object **when the collection actually changes**.\r\n\r\n```js\r\nimport Immutable from 'immutable'\r\n\r\nlet myMap = Immutable.Map({\r\n  a: 1,\r\n  b: 2,\r\n  c: 3\r\n})\r\n\r\n // set, merge and others only return a new obj when update changes collection\r\nlet newMap = myMap.set('a', 1)\r\nassert.equal(myMap, newMap)\r\nnewMap = myMap.merge({ 'a': 1 })\r\nassert.equal(myMap, newMap)\r\n// map, reduce, filter and others always return a new obj\r\nnewMap = myMap.map(a => a * 1)\r\nassert.notEqual(myMap, newMap)\r\n```\r\n\r\nIf a selector's input is updated by an operation that always returns a new object, it may be performing unnecessary recomputations. See [here](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same) for a discussion on the pros and cons of using a deep equality check like `Immutable.is` to eliminate unnecessary recomputations.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n* Create a factory function which returns a new selector for each instance of the component. There is built-in support for factory functions in React Redux v4.3 or higher. See [here](#sharing-selectors-with-props-across-multiple-component-instances) for an example.\r\n\r\n* Create a custom selector with a cache size greater than one.\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! They are included and referenced in `package.json`. They should Just Work™.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n* Measure selector recomputations across the app and identify performance bottlenecks\r\n* Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n* Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n* Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n* Highlight most recomputed selectors\r\n* Dependency Graph\r\n* Search by Selectors Graph\r\n* Selectors Inputs\r\n* Selectors Output (In case if selector not dependent from external arguments)\r\n* Shows \"Not Memoized (NM)\" selectors\r\n\r\n### [reselect-map](https://github.com/HeyImAlex/reselect-map)\r\n\r\nCan be useful when doing **very expensive** computations on elements of a collection because Reselect might not give you the granularity of caching that you need. Check out the reselect-maps README for examples.\r\n\r\n**The optimizations in reselect-map only apply in a small number of cases. If you are unsure whether you need it, you don't!**\r\n\r\n## License\r\n\r\nMIT\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"f202c14b322064922a86309e3821814bc89fd3ca","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/index.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/index.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","_nodeVersion":"14.17.0","dependencies":{},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2.0":{"*":["src/typesVersions/ts4.1/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","jest":"^26.6.1","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","rollup":"^2.38.5","ts-jest":"26.5.6","prettier":"^2.1.2","coveralls":"^2.11.4","cross-env":"^7.0.2","@babel/cli":"^7.12.13","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.12.13","@types/jest":"^27.0.2","@types/lodash":"^4.14.175","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","@babel/register":"^7.12.13","@babel/preset-env":"^7.12.13","eslint-plugin-react":"^5.1.1","@rollup/plugin-babel":"^5.2.3","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^2.3.3","@rollup/plugin-commonjs":"^15.1.0","@babel/preset-typescript":"^7.14.5","@microsoft/api-extractor":"^7.18.1","@rollup/plugin-node-resolve":"^9.0.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.0-alpha.1_1634507862518_0.3732946752985997","host":"s3://npm-registry-packages"}},"4.1.0-alpha.2":{"name":"reselect","version":"4.1.0-alpha.2","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.0-alpha.2","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"c8fdd459bd9a56dd932abe66fc664c007cdd6c2e","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.0-alpha.2.tgz","fileCount":17,"integrity":"sha512-pH2OiVDkkQrcMPdD631uLsfEVxEghqjjN7Yla7IU6aXJ1v5/ov6yNLQh2fjUT7IhLhw83rEQn8QA3QyBTa1Z5w==","signatures":[{"sig":"MEQCIDRyDwMcleXADXRvsBP08UjnmryrnXDJ3O0pe2ggIhoaAiBtRdN3R900nJNbq/BU7dSrSe0MVfjm/Q14H8fdYQegZA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":153847},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","readme":"# Reselect\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\nSimple “selector” library for Redux (and others) inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nYou can play around with the following **example** in [this codepen](https://codepen.io/Domiii/pen/LzGNWj?editors=0010):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  taxSelector,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n- [Example](#example)\r\n  - [Motivation for Memoized Selectors](#motivation-for-memoized-selectors)\r\n  - [Creating a Memoized Selector](#creating-a-memoized-selector)\r\n  - [Composing Selectors](#composing-selectors)\r\n  - [Connecting a Selector to the Redux Store](#connecting-a-selector-to-the-redux-store)\r\n  - [Accessing React Props in Selectors](#accessing-react-props-in-selectors)\r\n  - [Sharing Selectors with Props Across Multiple Component Instances](#sharing-selectors-with-props-across-multiple-component-instances)\r\n- [API](#api)\r\n  - [`createSelector`](#createselectorinputselectors--inputselectors-resultfunc)\r\n  - [`defaultMemoize`](#defaultmemoizefunc-equalitycheck--defaultequalitycheck)\r\n  - [`createSelectorCreator`](#createselectorcreatormemoize-memoizeoptions)\r\n  - [`createStructuredSelector`](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [FAQ](#faq)\r\n\r\n  - [Why isn't my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [How do I create a selector that takes an argument? ](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n  - [Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript typings?](#q-are-there-typescript-typings)\r\n  - [How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n\r\n## Installation\r\n\r\n    npm install reselect\r\n\r\n## Example\r\n\r\nIf you prefer a video tutorial, you can find one [here](https://www.youtube.com/watch?v=6Xwo5mVxDqI).\r\n\r\n### Motivation for Memoized Selectors\r\n\r\n> The examples in this section are based on the [Redux Todos List example](https://redux.js.org/recipes/computing-derived-data/).\r\n\r\n#### `features/todos/VisibleTodoList.js`\r\n\r\n```js\r\nimport { useSelector } from 'react-redux'\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from './todosSlice'\r\nimport TodoList from './TodoList'\r\n\r\nconst selectVisibleTodos = (todos, filter) => {\r\n  switch (filter) {\r\n    case 'SHOW_ALL':\r\n      return todos\r\n    case 'SHOW_COMPLETED':\r\n      return todos.filter(t => t.completed)\r\n    case 'SHOW_ACTIVE':\r\n      return todos.filter(t => !t.completed)\r\n  }\r\n}\r\n\r\nconst mapStateToProps = state => {\r\n  return {\r\n    todos: selectVisibleTodos(state.todos, state.visibilityFilter)\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(mapStateToProps, { toggleTodo })(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\nIn the above example, `mapStateToProps` calls `selectVisibleTodos` to calculate `todos`. This works great, but there is a drawback: `todos` is calculated every time the state tree is updated. If the state tree is large, or the calculation expensive, repeating the calculation on every update may cause performance problems. Reselect can help to avoid these unnecessary recalculations.\r\n\r\n### Creating a Memoized Selector\r\n\r\nWe would like to replace `selectVisibleTodos` with a memoized selector that recalculates `todos` when the value of `state.todos` or `state.visibilityFilter` changes, but not when changes occur in other (unrelated) parts of the state tree.\r\n\r\nReselect provides a function `createSelector` for creating memoized selectors. `createSelector` takes an array of input-selectors and a transform function as its arguments. If the Redux state tree is mutated in a way that causes the value of an input-selector to change, the selector will call its transform function with the values of the input-selectors as arguments and return the result. If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.\r\n\r\nLet's define a memoized selector named `selectVisibleTodos` to replace the non-memoized version above:\r\n\r\n#### `features/todos/todoSelectors`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectVisibilityFilter = state => state.visibilityFilter\r\nconst selectTodos = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  [selectVisibilityFilter, selectTodos],\r\n  (visibilityFilter, todos) => {\r\n    switch (visibilityFilter) {\r\n      case 'SHOW_ALL':\r\n        return todos\r\n      case 'SHOW_COMPLETED':\r\n        return todos.filter(t => t.completed)\r\n      case 'SHOW_ACTIVE':\r\n        return todos.filter(t => !t.completed)\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIn the example above, `selectVisibilityFilter` and `selectTodos` are input-selectors. They are created as ordinary non-memoized selector functions because they do not transform the data they select. `selectVisibleTodos` on the other hand is a memoized selector. It takes `selectVisibilityFilter` and `selectTodos` as input-selectors, and a transform function that calculates the filtered todos list.\r\n\r\n### Composing Selectors\r\n\r\nA memoized selector can itself be an input-selector to another memoized selector. Here is `selectVisibleTodos` being used as an input-selector to a selector that further filters the todos by keyword:\r\n\r\n```js\r\nconst selectKeyword = state => state.keyword\r\n\r\nconst selectVisibleTodosFilteredByKeyword = createSelector(\r\n  [selectVisibleTodos, selectKeyword],\r\n  (visibleTodos, keyword) =>\r\n    visibleTodos.filter(todo => todo.text.includes(keyword))\r\n)\r\n```\r\n\r\n### Connecting a Selector to the Redux Store\r\n\r\nIf you are using [React Redux](https://github.com/reduxjs/react-redux), you can call selectors as regular functions inside `mapStateToProps()`:\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { selectVisibleTodos } from '../selectors'\r\n\r\nconst mapStateToProps = state => {\r\n  return {\r\n    todos: selectVisibleTodos(state)\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(mapStateToProps, { toggleTodo })(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\n### Accessing React Props in Selectors\r\n\r\n> This section introduces a hypothetical extension to our app that allows it to support multiple Todo Lists. Please note that a full implementation of this extension requires changes to the reducers, components, actions etc. that aren’t directly relevant to the topics discussed and have been omitted for brevity.\r\n\r\nSo far we have only seen selectors receive the Redux store state as an argument, but a selector can receive props too.\r\n\r\nHere is an `App` component that renders three `VisibleTodoList` component instances, each of which has a `listId` prop:\r\n\r\n#### `components/App.js`\r\n\r\n```js\r\nimport React from 'react'\r\nimport Footer from './Footer'\r\nimport AddTodo from '../containers/AddTodo'\r\nimport VisibleTodoList from '../containers/VisibleTodoList'\r\n\r\nconst App = () => (\r\n  <div>\r\n    <VisibleTodoList listId=\"1\" />\r\n    <VisibleTodoList listId=\"2\" />\r\n    <VisibleTodoList listId=\"3\" />\r\n  </div>\r\n)\r\n```\r\n\r\nEach `VisibleTodoList` container should select a different slice of the state depending on the value of the `listId` prop, so let’s modify `selectVisibilityFilter` and `selectTodos` to accept a props argument:\r\n\r\n#### `selectors/todoSelectors.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectVisibilityFilter = (state, props) =>\r\n  state.todoLists[props.listId].visibilityFilter\r\n\r\nconst selectTodos = (state, props) => state.todoLists[props.listId].todos\r\n\r\nconst selectVisibleTodos = createSelector(\r\n  [selectVisibilityFilter, selectTodos],\r\n  (visibilityFilter, todos) => {\r\n    switch (visibilityFilter) {\r\n      case 'SHOW_COMPLETED':\r\n        return todos.filter(todo => todo.completed)\r\n      case 'SHOW_ACTIVE':\r\n        return todos.filter(todo => !todo.completed)\r\n      default:\r\n        return todos\r\n    }\r\n  }\r\n)\r\n\r\nexport default selectVisibleTodos\r\n```\r\n\r\n`props` can be passed to `selectVisibleTodos` from `mapStateToProps`:\r\n\r\n```js\r\nconst mapStateToProps = (state, props) => {\r\n  return {\r\n    todos: selectVisibleTodos(state, props)\r\n  }\r\n}\r\n```\r\n\r\nSo now `selectVisibleTodos` has access to `props`, and everything seems to be working fine.\r\n\r\n**But there is a problem!**\r\n\r\nUsing the `selectVisibleTodos` selector with multiple instances of the `VisibleTodoList` container will not correctly memoize:\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { selectVisibleTodos } from '../selectors'\r\n\r\nconst mapStateToProps = (state, props) => {\r\n  return {\r\n    // WARNING: THE FOLLOWING SELECTOR DOES NOT CORRECTLY MEMOIZE\r\n    todos: selectVisibleTodos(state, props)\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(mapStateToProps, { toggleTodo })(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\nA selector created with `createSelector` has a cache size of 1 and only returns the cached value when its set of arguments is the same as its previous set of arguments. If we alternate between rendering `<VisibleTodoList listId=\"1\" />` and `<VisibleTodoList listId=\"2\" />`, the shared selector will alternate between receiving `{listId: 1}` and `{listId: 2}` as its `props` argument. This will cause the arguments to be different on each call, so the selector will always recompute instead of returning the cached value. We’ll see how to overcome this limitation in the next section.\r\n\r\n### Sharing Selectors with Props Across Multiple Component Instances\r\n\r\n> The examples in this section require React Redux v4.3.0 or greater\r\n\r\n> An alternative approach can be found in [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nTo share a selector across multiple `VisibleTodoList` instances while passing in `props` **and** retaining memoization, each instance of the component needs its own private copy of the selector.\r\n\r\nLet’s create a function named `makeSelectVisibleTodos` that returns a new copy of the `selectVisibleTodos` selector each time it is called:\r\n\r\n#### `selectors/todoSelectors.js`\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectVisibilityFilter = (state, props) =>\r\n  state.todoLists[props.listId].visibilityFilter\r\n\r\nconst selectTodos = (state, props) => state.todoLists[props.listId].todos\r\n\r\nconst makeSelectVisibleTodos = () => {\r\n  return createSelector(\r\n    [selectVisibilityFilter, selectTodos],\r\n    (visibilityFilter, todos) => {\r\n      switch (visibilityFilter) {\r\n        case 'SHOW_COMPLETED':\r\n          return todos.filter(todo => todo.completed)\r\n        case 'SHOW_ACTIVE':\r\n          return todos.filter(todo => !todo.completed)\r\n        default:\r\n          return todos\r\n      }\r\n    }\r\n  )\r\n}\r\n\r\nexport default makeSelectVisibleTodos\r\n```\r\n\r\nWe also need a way to give each instance of a container access to its own private selector. The `mapStateToProps` argument of `connect` can help with this.\r\n\r\n**If the `mapStateToProps` argument supplied to `connect` returns a function instead of an object, it will be used to create an individual `mapStateToProps` function for each instance of the container.**\r\n\r\nIn the example below `makeMapStateToProps` creates a new `selectVisibleTodos` selector, and returns a `mapStateToProps` function that has exclusive access to the new selector:\r\n\r\n```js\r\nconst makeMapStateToProps = () => {\r\n  const selectVisibleTodos = makeSelectVisibleTodos()\r\n  const mapStateToProps = (state, props) => {\r\n    return {\r\n      todos: selectVisibleTodos(state, props)\r\n    }\r\n  }\r\n  return mapStateToProps\r\n}\r\n```\r\n\r\nIf we pass `makeMapStateToProps` to `connect`, each instance of the `VisibleTodoList` container will select its own `mapStateToProps` function with a private `selectVisibleTodos` selector. Memoization will now work correctly regardless of the render order of the `VisibleTodoList` containers.\r\n\r\n#### `containers/VisibleTodoList.js`\r\n\r\n```js\r\nimport { connect } from 'react-redux'\r\nimport { toggleTodo } from '../actions'\r\nimport TodoList from '../components/TodoList'\r\nimport { makeSelectVisibleTodos } from '../selectors'\r\n\r\nconst makeMapStateToProps = () => {\r\n  const selectVisibleTodos = makeSelectVisibleTodos()\r\n  const mapStateToProps = (state, props) => {\r\n    return {\r\n      todos: selectVisibleTodos(state, props)\r\n    }\r\n  }\r\n  return mapStateToProps\r\n}\r\n\r\nconst mapDispatchToProps = dispatch => {\r\n  return {\r\n    onTodoClick: id => {\r\n      dispatch(toggleTodo(id))\r\n    }\r\n  }\r\n}\r\n\r\nconst VisibleTodoList = connect(\r\n  makeMapStateToProps,\r\n  mapDispatchToProps\r\n)(TodoList)\r\n\r\nexport default VisibleTodoList\r\n```\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc)\r\n\r\nTakes one or more selectors, or an array of selectors, computes their values and passes them as arguments to `resultFunc`.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nSelectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector.\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n```\r\n\r\nIt can be useful to access the props of a component from within a selector. When a selector is connected to a component with `connect`, the component props are passed as the second argument to the selector:\r\n\r\n```js\r\nconst selectAB = (state, props) => state.a * props.b\r\n\r\n// props only (ignoring state argument)\r\nconst selectC = (_, props) => props.c\r\n\r\n// state only (props argument omitted as not required)\r\nconst selectD = state => state.d\r\n\r\nconst totalSelector = createSelector(\r\n  selectAB,\r\n  selectC,\r\n  selectD,\r\n  (ab, c, d) => ({\r\n    total: ab + c + d\r\n  })\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheck = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a cache size of 1. This means it always recalculates when the value of an argument changes.\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\n`defaultMemoize` can be used with `createSelectorCreator` to [customize the `equalityCheck` function](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It is currently being used successfully in traditional Flux apps.\r\n\r\n> If you create selectors using `createSelector` make sure its arguments are immutable.\r\n> See [here](#createselectorinputselectors--inputselectors-resultfunc)\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nA: Keep in mind that selectors can access React props, so if your arguments are (or can be made available as) React props, you can use that functionality. [See here](#accessing-react-props-in-selectors) for details.\r\n\r\nOtherwise, Reselect doesn't have built-in support for creating selectors that accepts arguments, but here are some suggestions for implementing similar functionality...\r\n\r\nIf the argument is not dynamic you can use a factory function:\r\n\r\n```js\r\nconst expensiveItemSelectorFactory = minValue => {\r\n  return createSelector(shopItemsSelector, items =>\r\n    items.filter(item => item.value > minValue)\r\n  )\r\n}\r\n\r\nconst selectSubtotal = createSelector(\r\n  expensiveItemSelectorFactory(200),\r\n  items => items.reduce((acc, item) => acc + item.value, 0)\r\n)\r\n```\r\n\r\nThe general consensus [here](https://github.com/reduxjs/reselect/issues/38) and [over at nuclear-js](https://github.com/optimizely/nuclear-js/issues/14) is that if a selector needs a dynamic argument, then that argument should probably be state in the store. If you decide that you do require a selector with a dynamic argument, then a selector that returns a memoized function may be suitable:\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst expensiveSelector = createSelector(\r\n  state => state.items,\r\n  items => memoize(minValue => items.filter(item => item.value > minValue))\r\n)\r\n\r\nconst expensiveFilter = expensiveSelector(state)\r\n\r\nconst slightlyExpensive = expensiveFilter(100)\r\nconst veryExpensive = expensiveFilter(1000000)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: How do I use Reselect with Immutable.js?\r\n\r\nA: Selectors created with `createSelector` should work just fine with Immutable.js data structures.\r\n\r\nIf your selector is recomputing and you don't think the state has changed, make sure you are aware of which Immutable.js update methods **always** return a new object and which update methods only return a new object **when the collection actually changes**.\r\n\r\n```js\r\nimport Immutable from 'immutable'\r\n\r\nlet myMap = Immutable.Map({\r\n  a: 1,\r\n  b: 2,\r\n  c: 3\r\n})\r\n\r\n// set, merge and others only return a new obj when update changes collection\r\nlet newMap = myMap.set('a', 1)\r\nassert.equal(myMap, newMap)\r\nnewMap = myMap.merge({ a: 1 })\r\nassert.equal(myMap, newMap)\r\n// map, reduce, filter and others always return a new obj\r\nnewMap = myMap.map(a => a * 1)\r\nassert.notEqual(myMap, newMap)\r\n```\r\n\r\nIf a selector's input is updated by an operation that always returns a new object, it may be performing unnecessary recomputations. See [here](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same) for a discussion on the pros and cons of using a deep equality check like `Immutable.is` to eliminate unnecessary recomputations.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. There is built-in support for factory functions in React Redux v4.3 or higher. See [here](#sharing-selectors-with-props-across-multiple-component-instances) for an example.\r\n\r\n- Create a custom selector with a cache size greater than one.\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! They are included and referenced in `package.json`. They should Just Work™.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n### [reselect-map](https://github.com/HeyImAlex/reselect-map)\r\n\r\nCan be useful when doing **very expensive** computations on elements of a collection because Reselect might not give you the granularity of caching that you need. Check out the reselect-maps README for examples.\r\n\r\n**The optimizations in reselect-map only apply in a small number of cases. If you are unsure whether you need it, you don't!**\r\n\r\n## License\r\n\r\nMIT\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"dc3e9d1d86fca6449df631955515f1be5d1a8bd9","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","_nodeVersion":"14.17.0","dependencies":{"memoize-one":"^6.0.0-beta.1","micro-memoize":"^4.0.9"},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2.0":{"*":["src/typesVersions/ts4.1/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"ncp":"^2.0.0","nyc":"^6.4.0","chai":"^3.0.0","jest":"^26.6.1","mocha":"^2.2.5","eslint":"^2.11","mkdirp":"^0.5.1","rollup":"^2.38.5","ts-jest":"26.5.6","prettier":"^2.1.2","coveralls":"^2.11.4","cross-env":"^7.0.2","@babel/cli":"^7.12.13","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.12.13","@types/jest":"^27.0.2","@types/lodash":"^4.14.175","better-npm-run":"0.0.8","lodash.memoize":"^4.1.0","@babel/register":"^7.12.13","@babel/preset-env":"^7.12.13","eslint-plugin-react":"^5.1.1","@rollup/plugin-babel":"^5.2.3","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^2.3.3","@rollup/plugin-commonjs":"^15.1.0","@babel/preset-typescript":"^7.14.5","@microsoft/api-extractor":"^7.18.1","@rollup/plugin-node-resolve":"^9.0.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.0-alpha.2_1634698273249_0.4973923381085481","host":"s3://npm-registry-packages"}},"4.1.0-beta.0":{"name":"reselect","version":"4.1.0-beta.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.0-beta.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"dbd4c0e1f4d4f9c98debfd64a6f1c0338b4aff1a","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.0-beta.0.tgz","fileCount":17,"integrity":"sha512-9HRzj3Vze/AE4vZIJiA7ajDG3KtCWVUoHYvwrXfft/TRZp4XemsDcYeVqyUCgC3RXxf9FWLxrYUvjrqIsX2Zog==","signatures":[{"sig":"MEUCIQDls8o0MY5gl90pdOqtYDywPcMsER+U6UtNerIZQxWg3gIga2Kfz3mdGsLJsPlrYMe52ElPSaRTpOuuR0LuNjTCbZw=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":156177},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","readme":"# Reselect\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\nYou can play around with the following **example** in [this codepen](https://codepen.io/Domiii/pen/LzGNWj?editors=0010):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  taxSelector,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Reselect](#reselect)\r\n\r\n  - [Table of Contents](#table-of-contents)\r\n  - [Installation](#installation)\r\n  - [Usage Guide](#usage-guide)\r\n  - [API](#api)\r\n    - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n    - [defaultMemoize(func, equalityCheck = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheck--defaultequalitycheck)\r\n    - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n      - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n      - [Use memoize function from lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n    - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n  - [FAQ](#faq)\r\n    - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n    - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n    - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n    - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n    - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n    - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n    - [Q: How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n    - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n    - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n    - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n  - [Related Projects](#related-projects)\r\n    - [re-reselect](#re-reselect)\r\n    - [reselect-tools](#reselect-tools)\r\n    - [reselect-debugger](#reselect-debugger)\r\n    - [reselect-map](#reselect-map)\r\n  - [License](#license)\r\n\r\n  - [Why isn't my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [How do I create a selector that takes an argument? ](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n  - [Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript typings?](#q-are-there-typescript-typings)\r\n  - [How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Usage Guide\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors]()** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nTakes one or more selectors, or an array of selectors, computes their values and passes them as arguments to `resultFunc`.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIt can be useful to access the props of a component from within a selector. When a selector is connected to a component with `connect`, the component props are passed as the second argument to the selector:\r\n\r\n```js\r\nconst selectAB = (state, props) => state.a * props.b\r\n\r\n// props only (ignoring state argument)\r\nconst selectC = (_, props) => props.c\r\n\r\n// state only (props argument omitted as not required)\r\nconst selectD = state => state.d\r\n\r\nconst totalSelector = createSelector(\r\n  selectAB,\r\n  selectC,\r\n  selectD,\r\n  (ab, c, d) => ({\r\n    total: ab + c + d\r\n  })\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size.\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\n`defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It is currently being used successfully in traditional Flux apps.\r\n\r\n> If you create selectors using `createSelector` make sure its arguments are immutable.\r\n> See [here](#createselectorinputselectors--inputselectors-resultfunc)\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nA: Keep in mind that selectors can access React props, so if your arguments are (or can be made available as) React props, you can use that functionality. [See here](#accessing-react-props-in-selectors) for details.\r\n\r\nOtherwise, Reselect doesn't have built-in support for creating selectors that accepts arguments, but here are some suggestions for implementing similar functionality...\r\n\r\nIf the argument is not dynamic you can use a factory function:\r\n\r\n```js\r\nconst expensiveItemSelectorFactory = minValue => {\r\n  return createSelector(shopItemsSelector, items =>\r\n    items.filter(item => item.value > minValue)\r\n  )\r\n}\r\n\r\nconst selectSubtotal = createSelector(\r\n  expensiveItemSelectorFactory(200),\r\n  items => items.reduce((acc, item) => acc + item.value, 0)\r\n)\r\n```\r\n\r\nThe general consensus [here](https://github.com/reduxjs/reselect/issues/38) and [over at nuclear-js](https://github.com/optimizely/nuclear-js/issues/14) is that if a selector needs a dynamic argument, then that argument should probably be state in the store. If you decide that you do require a selector with a dynamic argument, then a selector that returns a memoized function may be suitable:\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst expensiveSelector = createSelector(\r\n  state => state.items,\r\n  items => memoize(minValue => items.filter(item => item.value > minValue))\r\n)\r\n\r\nconst expensiveFilter = expensiveSelector(state)\r\n\r\nconst slightlyExpensive = expensiveFilter(100)\r\nconst veryExpensive = expensiveFilter(1000000)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: How do I use Reselect with Immutable.js?\r\n\r\nA: Selectors created with `createSelector` should work just fine with Immutable.js data structures.\r\n\r\nIf your selector is recomputing and you don't think the state has changed, make sure you are aware of which Immutable.js update methods **always** return a new object and which update methods only return a new object **when the collection actually changes**.\r\n\r\n```js\r\nimport Immutable from 'immutable'\r\n\r\nlet myMap = Immutable.Map({\r\n  a: 1,\r\n  b: 2,\r\n  c: 3\r\n})\r\n\r\n// set, merge and others only return a new obj when update changes collection\r\nlet newMap = myMap.set('a', 1)\r\nassert.equal(myMap, newMap)\r\nnewMap = myMap.merge({ a: 1 })\r\nassert.equal(myMap, newMap)\r\n// map, reduce, filter and others always return a new obj\r\nnewMap = myMap.map(a => a * 1)\r\nassert.notEqual(myMap, newMap)\r\n```\r\n\r\nIf a selector's input is updated by an operation that always returns a new object, it may be performing unnecessary recomputations. See [here](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same) for a discussion on the pros and cons of using a deep equality check like `Immutable.is` to eliminate unnecessary recomputations.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. There is built-in support for factory functions in React Redux v4.3 or higher. See [here](#sharing-selectors-with-props-across-multiple-component-instances) for an example.\r\n\r\n- Create a custom selector with a cache size greater than one.\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n### [reselect-map](https://github.com/HeyImAlex/reselect-map)\r\n\r\nCan be useful when doing **very expensive** computations on elements of a collection because Reselect might not give you the granularity of caching that you need. Check out the reselect-maps README for examples.\r\n\r\n**The optimizations in reselect-map only apply in a small number of cases. If you are unsure whether you need it, you don't!**\r\n\r\n## License\r\n\r\nMIT\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"a3fcacf775ca980fc7f778ca53a4a8804c9b725a","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","_nodeVersion":"14.17.0","dependencies":{"tslint":"6.1.3","memoize-one":"^6.0.0","micro-memoize":"^4.0.9"},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2.0":{"*":["src/typesVersions/ts4.1/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rollup":"^2.58.0","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","@types/lodash":"^4.14.175","better-npm-run":"0.1.1","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.0-beta.0_1634782821614_0.02135017436880693","host":"s3://npm-registry-packages"}},"4.1.0-beta.1":{"name":"reselect","version":"4.1.0-beta.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.0-beta.1","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"302513f8e3fd727bd220034e749e39a0fa83658e","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.0-beta.1.tgz","fileCount":17,"integrity":"sha512-q4FEKJa0vNqmClqMugsR/2ZKxaLycWih9ZtxvEzCau1AKb98ZsSNqEMHfcTM2nAOn5ctJ8xPOI+qFaTSxKakKA==","signatures":[{"sig":"MEUCIQCrkzqQWkahBiPWeZvcBDDsDkjc5s2KEB8MeOQyoTs7IQIgCLBT0rPkQUYWlOU6jRtamuzB5fYlLCcOHG4YDPyuCd8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":156199},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","readme":"# Reselect\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\nYou can play around with the following **example** in [this codepen](https://codepen.io/Domiii/pen/LzGNWj?editors=0010):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  taxSelector,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Reselect](#reselect)\r\n\r\n  - [Table of Contents](#table-of-contents)\r\n  - [Installation](#installation)\r\n  - [Usage Guide](#usage-guide)\r\n  - [API](#api)\r\n    - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n    - [defaultMemoize(func, equalityCheck = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheck--defaultequalitycheck)\r\n    - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n      - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n      - [Use memoize function from lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n    - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n  - [FAQ](#faq)\r\n    - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n    - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n    - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n    - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n    - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n    - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n    - [Q: How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n    - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n    - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n    - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n  - [Related Projects](#related-projects)\r\n    - [re-reselect](#re-reselect)\r\n    - [reselect-tools](#reselect-tools)\r\n    - [reselect-debugger](#reselect-debugger)\r\n    - [reselect-map](#reselect-map)\r\n  - [License](#license)\r\n\r\n  - [Why isn't my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [How do I create a selector that takes an argument? ](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n  - [Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript typings?](#q-are-there-typescript-typings)\r\n  - [How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Usage Guide\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors]()** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nTakes one or more selectors, or an array of selectors, computes their values and passes them as arguments to `resultFunc`.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIt can be useful to access the props of a component from within a selector. When a selector is connected to a component with `connect`, the component props are passed as the second argument to the selector:\r\n\r\n```js\r\nconst selectAB = (state, props) => state.a * props.b\r\n\r\n// props only (ignoring state argument)\r\nconst selectC = (_, props) => props.c\r\n\r\n// state only (props argument omitted as not required)\r\nconst selectD = state => state.d\r\n\r\nconst totalSelector = createSelector(\r\n  selectAB,\r\n  selectC,\r\n  selectD,\r\n  (ab, c, d) => ({\r\n    total: ab + c + d\r\n  })\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size.\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\n`defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It is currently being used successfully in traditional Flux apps.\r\n\r\n> If you create selectors using `createSelector` make sure its arguments are immutable.\r\n> See [here](#createselectorinputselectors--inputselectors-resultfunc)\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nA: Keep in mind that selectors can access React props, so if your arguments are (or can be made available as) React props, you can use that functionality. [See here](#accessing-react-props-in-selectors) for details.\r\n\r\nOtherwise, Reselect doesn't have built-in support for creating selectors that accepts arguments, but here are some suggestions for implementing similar functionality...\r\n\r\nIf the argument is not dynamic you can use a factory function:\r\n\r\n```js\r\nconst expensiveItemSelectorFactory = minValue => {\r\n  return createSelector(shopItemsSelector, items =>\r\n    items.filter(item => item.value > minValue)\r\n  )\r\n}\r\n\r\nconst selectSubtotal = createSelector(\r\n  expensiveItemSelectorFactory(200),\r\n  items => items.reduce((acc, item) => acc + item.value, 0)\r\n)\r\n```\r\n\r\nThe general consensus [here](https://github.com/reduxjs/reselect/issues/38) and [over at nuclear-js](https://github.com/optimizely/nuclear-js/issues/14) is that if a selector needs a dynamic argument, then that argument should probably be state in the store. If you decide that you do require a selector with a dynamic argument, then a selector that returns a memoized function may be suitable:\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst expensiveSelector = createSelector(\r\n  state => state.items,\r\n  items => memoize(minValue => items.filter(item => item.value > minValue))\r\n)\r\n\r\nconst expensiveFilter = expensiveSelector(state)\r\n\r\nconst slightlyExpensive = expensiveFilter(100)\r\nconst veryExpensive = expensiveFilter(1000000)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: How do I use Reselect with Immutable.js?\r\n\r\nA: Selectors created with `createSelector` should work just fine with Immutable.js data structures.\r\n\r\nIf your selector is recomputing and you don't think the state has changed, make sure you are aware of which Immutable.js update methods **always** return a new object and which update methods only return a new object **when the collection actually changes**.\r\n\r\n```js\r\nimport Immutable from 'immutable'\r\n\r\nlet myMap = Immutable.Map({\r\n  a: 1,\r\n  b: 2,\r\n  c: 3\r\n})\r\n\r\n// set, merge and others only return a new obj when update changes collection\r\nlet newMap = myMap.set('a', 1)\r\nassert.equal(myMap, newMap)\r\nnewMap = myMap.merge({ a: 1 })\r\nassert.equal(myMap, newMap)\r\n// map, reduce, filter and others always return a new obj\r\nnewMap = myMap.map(a => a * 1)\r\nassert.notEqual(myMap, newMap)\r\n```\r\n\r\nIf a selector's input is updated by an operation that always returns a new object, it may be performing unnecessary recomputations. See [here](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same) for a discussion on the pros and cons of using a deep equality check like `Immutable.is` to eliminate unnecessary recomputations.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. There is built-in support for factory functions in React Redux v4.3 or higher. See [here](#sharing-selectors-with-props-across-multiple-component-instances) for an example.\r\n\r\n- Create a custom selector with a cache size greater than one.\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n### [reselect-map](https://github.com/HeyImAlex/reselect-map)\r\n\r\nCan be useful when doing **very expensive** computations on elements of a collection because Reselect might not give you the granularity of caching that you need. Check out the reselect-maps README for examples.\r\n\r\n**The optimizations in reselect-map only apply in a small number of cases. If you are unsure whether you need it, you don't!**\r\n\r\n## License\r\n\r\nMIT\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"dea909a3261eedba875caa39578404c6c86ed005","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2.0":{"*":["src/typesVersions/ts4.1/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","better-npm-run":"0.1.1","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.0-beta.1_1634786410649_0.21007498359172505","host":"s3://npm-registry-packages"}},"4.1.0-beta.2":{"name":"reselect","version":"4.1.0-beta.2","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.0-beta.2","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"cfeed82250c8dd19e24cbcccc0cf0fe65d885dcc","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.0-beta.2.tgz","fileCount":17,"integrity":"sha512-EHxFXNjVW+M/a64APnJmox1m2R4ywkFJ0GT/LqaVwSCUhk74z61xHn8dT/lquybX5qhbVzkRN0jSO4HS23L/kg==","signatures":[{"sig":"MEQCIEL3WNuGIwtFKgl71kfeJVY2KutbSdZRUrBp8eIIbs4EAiBZPqz3DiKgODMjOMe77P5XJV1z0vX7YkGc8vXf7Cvd8w==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":156208},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","readme":"# Reselect\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\nYou can play around with the following **example** in [this codepen](https://codepen.io/Domiii/pen/LzGNWj?editors=0010):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  taxSelector,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Reselect](#reselect)\r\n\r\n  - [Table of Contents](#table-of-contents)\r\n  - [Installation](#installation)\r\n  - [Usage Guide](#usage-guide)\r\n  - [API](#api)\r\n    - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n    - [defaultMemoize(func, equalityCheck = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheck--defaultequalitycheck)\r\n    - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n      - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n      - [Use memoize function from lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n    - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n  - [FAQ](#faq)\r\n    - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n    - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n    - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n    - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n    - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n    - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n    - [Q: How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n    - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n    - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n    - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n  - [Related Projects](#related-projects)\r\n    - [re-reselect](#re-reselect)\r\n    - [reselect-tools](#reselect-tools)\r\n    - [reselect-debugger](#reselect-debugger)\r\n    - [reselect-map](#reselect-map)\r\n  - [License](#license)\r\n\r\n  - [Why isn't my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [How do I create a selector that takes an argument? ](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [How do I use Reselect with Immutable.js?](#q-how-do-i-use-reselect-with-immutablejs)\r\n  - [Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript typings?](#q-are-there-typescript-typings)\r\n  - [How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Usage Guide\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors]()** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nTakes one or more selectors, or an array of selectors, computes their values and passes them as arguments to `resultFunc`.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIt can be useful to access the props of a component from within a selector. When a selector is connected to a component with `connect`, the component props are passed as the second argument to the selector:\r\n\r\n```js\r\nconst selectAB = (state, props) => state.a * props.b\r\n\r\n// props only (ignoring state argument)\r\nconst selectC = (_, props) => props.c\r\n\r\n// state only (props argument omitted as not required)\r\nconst selectD = state => state.d\r\n\r\nconst totalSelector = createSelector(\r\n  selectAB,\r\n  selectC,\r\n  selectD,\r\n  (ab, c, d) => ({\r\n    total: ab + c + d\r\n  })\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size.\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\n`defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It is currently being used successfully in traditional Flux apps.\r\n\r\n> If you create selectors using `createSelector` make sure its arguments are immutable.\r\n> See [here](#createselectorinputselectors--inputselectors-resultfunc)\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nA: Keep in mind that selectors can access React props, so if your arguments are (or can be made available as) React props, you can use that functionality. [See here](#accessing-react-props-in-selectors) for details.\r\n\r\nOtherwise, Reselect doesn't have built-in support for creating selectors that accepts arguments, but here are some suggestions for implementing similar functionality...\r\n\r\nIf the argument is not dynamic you can use a factory function:\r\n\r\n```js\r\nconst expensiveItemSelectorFactory = minValue => {\r\n  return createSelector(shopItemsSelector, items =>\r\n    items.filter(item => item.value > minValue)\r\n  )\r\n}\r\n\r\nconst selectSubtotal = createSelector(\r\n  expensiveItemSelectorFactory(200),\r\n  items => items.reduce((acc, item) => acc + item.value, 0)\r\n)\r\n```\r\n\r\nThe general consensus [here](https://github.com/reduxjs/reselect/issues/38) and [over at nuclear-js](https://github.com/optimizely/nuclear-js/issues/14) is that if a selector needs a dynamic argument, then that argument should probably be state in the store. If you decide that you do require a selector with a dynamic argument, then a selector that returns a memoized function may be suitable:\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst expensiveSelector = createSelector(\r\n  state => state.items,\r\n  items => memoize(minValue => items.filter(item => item.value > minValue))\r\n)\r\n\r\nconst expensiveFilter = expensiveSelector(state)\r\n\r\nconst slightlyExpensive = expensiveFilter(100)\r\nconst veryExpensive = expensiveFilter(1000000)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: How do I use Reselect with Immutable.js?\r\n\r\nA: Selectors created with `createSelector` should work just fine with Immutable.js data structures.\r\n\r\nIf your selector is recomputing and you don't think the state has changed, make sure you are aware of which Immutable.js update methods **always** return a new object and which update methods only return a new object **when the collection actually changes**.\r\n\r\n```js\r\nimport Immutable from 'immutable'\r\n\r\nlet myMap = Immutable.Map({\r\n  a: 1,\r\n  b: 2,\r\n  c: 3\r\n})\r\n\r\n// set, merge and others only return a new obj when update changes collection\r\nlet newMap = myMap.set('a', 1)\r\nassert.equal(myMap, newMap)\r\nnewMap = myMap.merge({ a: 1 })\r\nassert.equal(myMap, newMap)\r\n// map, reduce, filter and others always return a new obj\r\nnewMap = myMap.map(a => a * 1)\r\nassert.notEqual(myMap, newMap)\r\n```\r\n\r\nIf a selector's input is updated by an operation that always returns a new object, it may be performing unnecessary recomputations. See [here](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same) for a discussion on the pros and cons of using a deep equality check like `Immutable.is` to eliminate unnecessary recomputations.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. There is built-in support for factory functions in React Redux v4.3 or higher. See [here](#sharing-selectors-with-props-across-multiple-component-instances) for an example.\r\n\r\n- Create a custom selector with a cache size greater than one.\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n### [reselect-map](https://github.com/HeyImAlex/reselect-map)\r\n\r\nCan be useful when doing **very expensive** computations on elements of a collection because Reselect might not give you the granularity of caching that you need. Check out the reselect-maps README for examples.\r\n\r\n**The optimizations in reselect-map only apply in a small number of cases. If you are unsure whether you need it, you don't!**\r\n\r\n## License\r\n\r\nMIT\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"a94302d37d902acb3db8a4e82392efe4936a2f13","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","better-npm-run":"0.1.1","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.0-beta.2_1635099982808_0.7539559850963313","host":"s3://npm-registry-packages"}},"4.1.0":{"name":"reselect","version":"4.1.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"903711c6c8e04ad4a99e5419dc6b08536d8329e0","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.0.tgz","fileCount":17,"integrity":"sha512-An39mlrk9bnL39pq9M6th54FaL7VaqZe2m8tBb746udYYO6MD7MOIdaqZ+tABkAOmHQSTqtL3NhUNE8HVvVcQQ==","signatures":[{"sig":"MEYCIQCOLZA9k/hD9kwrtj2vpkoNqHu1tqnrMh2q9xqeJ0Q1qwIhALgahfhLL6wOiHpigWKGYN2bFvH7ljL/pgRHByz0SI/m","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":154070},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"508e0dd84ead067dd9db85b9ab7ded5f5a69db1c","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","better-npm-run":"0.1.1","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.0_1635214465241_0.9246756309848658","host":"s3://npm-registry-packages"}},"4.1.1":{"name":"reselect","version":"4.1.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.1","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"7e2c110efbf3d70df3482604bcf2bc0ab571346a","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.1.tgz","fileCount":17,"integrity":"sha512-Jjt8Us6hAWJpjucyladHvUGR+q1mHHgWtGDXlhvvKyNyIeQ3bjuWLDX0bsTLhbm/gd4iXEACBlODUHBlLWiNnA==","signatures":[{"sig":"MEUCIQDsI81iUJ20zGIJyVQZ0dRF9FMxRGg7UMqGQgW1bGMFiQIgMhfcgFgMfHIhuVbem+m6HE9RhxgipisACipPZW3f21I=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":156101},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"0dab037cdeef83b40de88d9bb114a77541092c58","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"6.14.7","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"14.17.0","dependencies":{},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","better-npm-run":"0.1.1","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.1_1635292331651_0.5704475968905696","host":"s3://npm-registry-packages"}},"4.1.2":{"name":"reselect","version":"4.1.2","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.2","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"7bf642992d143d4f3b0f2dca8aa52018808a1d51","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.2.tgz","fileCount":16,"integrity":"sha512-wg60ebcPOtxcptIUfrr7Jt3h4BR86cCW3R7y4qt65lnNb4yz4QgrXcbSioVsIOYguyz42+XTHIyJ5TEruzkFgQ==","signatures":[{"sig":"MEYCIQDrkrjfE4GJauT8MmJzfRGW34D3FFmB8fI+NtZCTyKeYgIhAN8b1xp5y7HsKhhMKHQA/rt/eAKjH19TbyT8U58JZ9Z7","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":154134},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"d5e157f89485b58a8cd4a62e68ec35170b79912b","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"16.13.0","dependencies":{},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","better-npm-run":"0.1.1","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.2_1635990537984_0.04880881197064335","host":"s3://npm-registry-packages"}},"4.1.3":{"name":"reselect","version":"4.1.3","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.3","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"6307935d4ec661e77ede662be16fc9b39aa8f7ab","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.3.tgz","fileCount":16,"integrity":"sha512-TVpMknnmdSRNhLPgTDSCQKw32zt1ZIJtEcSxfL/ihtDqShEMUs2X2UY/g96YAVynUXxqLWSXObLGIcqKHQObHw==","signatures":[{"sig":"MEQCIH8Bl5AIw+aiOGYYuJ9xW6l1/U/Z79AVK5b71km90fqqAiBcZQhLoC0P0EvV9oXwYEuTULx99ub3AL1nLMXCxuVgbA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":167963,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhkx1/CRA9TVsSAnZWagAAIA8P/0GZU8pDC44/vqaFKj/Z\nNgy+UKl2wj/iebj4jZp0vXBfnM4ns4DZ175ofAeAnhQIH0Q6mw9TgXisG7D8\nHC4hpvtTokCKnLwiYoM3Nwc/WveCkJxO25aaSijvWOnF977Zy2fDsg0CwdBc\nSbpB4cRtOiRU0jOKE9f5IbasRBITGzbaqS9qkxliLvgmIdaNcA9wI+PhdKHt\nr3vxfJZM3NBEPmzAiqzefx6FPHknMgqlMxgB8XebOy5DJPK9U13AUomtZRHq\n7sAWrHzBNlDVyRfs88f7R4HKyWtzds7+D4LjqAe5qmuKg6kXEpDkJ83YJqvj\nLu5hddpBmxHrxd8SqmPxxyGaHs9sDUwX12DV1n7dWKDkXLu93ikXpIiDvmGS\n1DvaPPvLuqi/4sDB8gaY+7/gqNcsRovnMJ4W1i78k/LUTKxAOepSxoeSZuwI\ngE05sOacnY19MfEi5RIHU6/nJNOUtlht6mHwqSqWM0HZavBwyqDvXRRx/Vxx\n7iq47XN2SyHfQ9WwZOsrSi02K/f+s6lKpHLNe0AFFxTK84ihWHaFtl/42TmC\n74rttPyFwmXCRKMim3gLE3m0M5DdxOyp+2eRYPInzguXqxLNZYS8kNnrFJ/C\nmKfJ0RUvDpOZrMbUW+NrwDL129E8EcRLRJw4+XXHq+Sp9PR5hMhtOu56aNr6\nWdcG\r\n=ovbQ\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"9d899c10960f8bb42d375025d36605e21203ebfd","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && npm run build:types && npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"npm run build","test:typescript":"better-npm-run test:typescript"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"16.13.0","dependencies":{},"betterScripts":{"test":{"env":{"NODE_ENV":"test"},"command":"mocha --compilers js:@babel/register --ui tdd --recursive"},"test:cov":{"env":{"COVERAGE":"true","NODE_ENV":"test"},"command":"nyc --reporter=lcov --reporter=text mocha --compilers js:@babel/register --ui tdd"},"test:typescript":{"command":"tsc --noEmit -p typescript_test/tsconfig.json"},"compile:commonjs":{"env":{"BABEL_ENV":"cjs"},"command":"babel -d lib/ src/"}},"typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","better-npm-run":"0.1.1","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.3_1637031295206_0.20039361457224647","host":"s3://npm-registry-packages"}},"4.1.4":{"name":"reselect","version":"4.1.4","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.4","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"66df0aff41b6ee0f51e2cc17cfaf2c1995916f32","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.4.tgz","fileCount":16,"integrity":"sha512-i1LgXw8DKSU5qz1EV0ZIKz4yIUHJ7L3bODh+Da6HmVSm9vdL/hG7IpbgzQ3k2XSirzf8/eI7OMEs81gb1VV2fQ==","signatures":[{"sig":"MEUCIQC3eu9LQevixwrDoVCqVQ7SFJqGpqr7DhKK7LoW6TsHpwIgTxttBsrbReKW3x0mSMBxoBt2VOGNwoGcURxrUA9yCU8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":167597,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhlIgKCRA9TVsSAnZWagAAW9YP/R0LgtOCLKSkgDhCpKJL\nNoufsqJhLzh1Qx3lhXiXGyoiUPh3i98xijPRLaNg58rosXxXLfSmGFbENIez\nHd97qSVZVfO7t1l9a+jHwUkhY0/WUJVUUF0Bjb/oalM9T1BuzvXjbP+jbqe4\nfWOIr0yDs/HAyIeqDH8M5VMvpM23JnNMVActwuqCSRwa+Wy4mdpdJit9C2oT\nyyW4lQ8VCXiQ8+H90NBAxuiMGhPA7uypC4PU3v/3yTG9ubctqnt2M2ZO+jFW\nrYo5EkSXUUXT0gx4/wmFK9oWwKUUm71Loq/JzOki/yj/dAMwfanUTdprlQwH\nyY5qlYd3ZLOjTqSU8ucBEpH3zPfJ1Wig6qbm1rSnqriTDjKF1h5cM4su3IeQ\nEq2h2gsXHglvlfmuXJtl8LIGoKrgBtI1xBd49sUDR8bwn8Pk5L4AlVeD6jtt\nOGKcU1Kp/c6ZEwFgL4pto/feWTmdGFPaHgIb8+JftTr4t1iLfxHJqdbIKf5p\nnAJwRUdAE39RXOROeZaLDbpY1ufhAtE4eTYANed3WT5g1x/iqydPyShmox3g\nRTIf5RABEbi9wUVL0Up3TtiaWyyTrWAcjN5KqRkZUDvHVNln3vvgAKmzmi4L\niKjnNczeL3/AGBu70KzPorpM48YjpSfGI6n70QBu3aRNug1kYrdJZTdvaYAY\nmOks\r\n=PeK8\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"d7131c0fb31a0a00f867b1f92cb4af6235bef3cb","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && yarn build:types && yarn build:commonjs && yarn build:es && yarn build:umd && yarn build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"yarn build","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"16.13.0","typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rimraf":"^3.0.2","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","react-redux":"^7.2.6","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@reduxjs/toolkit":"^1.6.2","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.4_1637124106708_0.9111284022475674","host":"s3://npm-registry-packages"}},"4.1.5":{"name":"reselect","version":"4.1.5","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.5","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"852c361247198da6756d07d9296c2b51eddb79f6","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz","fileCount":16,"integrity":"sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==","signatures":[{"sig":"MEYCIQCdYki1LgWdBxa1o8enCQGfW45HtXrmrr9tiyLHRA9jTgIhAPl3CaBtOMw45R9DjAoXsQB48747OHqh0vT4bR6WGybA","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":168944,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnq3GCRA9TVsSAnZWagAAQs8P/jDVplD3kKRLQhesm31i\nKZwVvittnJymRX1X4M0aOq8ORZi3qilHL2FglYv/826Nxd8aHKDT365DfQ7u\nJmegeQWtHTsIFB7TY+xv6O1Btcrkg+s6LFaFPJM5xDeDJoLZy/XMCmFmmrcg\nZcc9aSZvtQ+HHwc3ARVARMK0bPYMycMaN5JQWv81iGuXB00Om6vjVHpt5+PD\n3zOwykvDmW+oZROYzdUIs+oAgKn1fS1g88WaoQAHPlo2v39zosDn9xbmF5sO\nOkh0xQWoYTp+CcCECwM5kbI6XyZNlAXgTImnU3AcQIodoyXGoVG3gsHZ3jWR\nuV8U38QAKTbNLWEhsFRk86Ci7PP7V5RMeu57TRUrahUk70wGvQIKx6ckQsrN\nq4I+eAzYvM4KsaOTgJvnhpjLKUBkeJmn/oke6HEgM8jirDg/4IXobHiUW0C6\n2pyYbV4YNyri7DQXPNmhEXGXozdkDPJ/66wAYxt8crWI1Opfi2t22OrAHHiO\nKZDrrDJcGkSlX5uDN81IwA3cJfJ7XGHoye1NSH/VTsUWU1Db4784vrLddHQv\nLvpW+ecTRLAdwpnYjdcLEaRkDyjLJCe2Kaj6LBZSRqH5auXfgZ8zJjDuZTZh\no9FmMoZaLn5P/vAyzFbaeBVfi5DFp1YaKW6aQfKXOq08p9jfnlZ7I+u+11Yh\nmnc2\r\n=jUXe\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"2f892bb92e1e7f2a525b3adc7d213f2d1e570f32","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && yarn build:types && yarn build:commonjs && yarn build:es && yarn build:umd && yarn build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"yarn build","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.1.2","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"16.13.0","typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rimraf":"^3.0.2","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","react-redux":"^7.2.6","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@reduxjs/toolkit":"^1.6.2","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.5_1637789126448_0.2949180038707728","host":"s3://npm-registry-packages"}},"4.1.6":{"name":"reselect","version":"4.1.6","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.6","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"19ca2d3d0b35373a74dc1c98692cdaffb6602656","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz","fileCount":16,"integrity":"sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==","signatures":[{"sig":"MEQCIBwuY4y/p8q2Qy4jHyjHamJNBb3p1lBQVJu6YiObTdgbAiBrnABJGV/FUQkUN1ul/XnodsdI1gisnyNruNeXZX4yyA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":168785,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJinpaeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoiqQ//cz+mZCXHBVURtWyRlLDKrHElNwz91Q6Q51FrXZcklRCZ90lA\r\nUN9HD1x3R9e504ZK/lKfV2lBvXxXlWhf7NA+S0Z1curR97Vd002t4bZLiQfF\r\n35lN9T/HxIHicldphDNgvP7z4/QVT0hrWLPa3ICuRswZRMLpJpSrw7AMUpF+\r\nXcpeLI7EWi4LEDQhpB9wC8azFzlvEP/dXza+Cignnqbm6Dr4RAQXQsURQvZX\r\n1iHrcUyLE6B0AQkGAy7o9esDIqOvhgXSfzwQapIxc6JCzdN87AuESe3Zqc7n\r\nkgvVLyStFhEqjhofqWqjgEgu5B3ApdH2yx7Nn1sXuWpt8KsunLe4OGLEeRF3\r\n4p0od1T/8FnLkYeTZkha3uRIeFQQn7WkjizIZ+TJhBnbfyHvKU49H6qzX4Ed\r\nP8IDKVZnAKseBtyXGwXuSVDvQrnBfl482bZDT8WzMCpKm/BDTesCVLHVK2H6\r\nykKlM0HaN3hFB1YLoZ8NnMu+tSQPaVlsZbMVDx3n4qTHOs7pylv4Pc7LptYT\r\nWbNuG8LXhCo7rg4fYgUHRyoPbtjH0PnV77zBnFSbg6+wCVRNatpZsv+PIKd8\r\nM4LvayjqFw4Ij7V6wjxLPVBBCc1jlh07UoR4iU9FWn8frnFdpERD+KkzyF3l\r\nXjqmHUodoWCmpBJQFxSWOyW2Sga5pP23/b8=\r\n=tNA8\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"d49e4e1145d919c62f6346713f02362b266df7d0","scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && yarn build:types && yarn build:commonjs && yarn build:es && yarn build:umd && yarn build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"yarn build","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.3.1","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"16.14.0","typesVersions":{"<4.2":{"*":["./src/typesVersions/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rimraf":"^3.0.2","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.4.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"^4.4.0","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","react-redux":"^7.2.6","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@reduxjs/toolkit":"^1.6.2","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.6_1654560414396_0.12662561945532125","host":"s3://npm-registry-packages"}},"4.1.7":{"name":"reselect","version":"4.1.7","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.7","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"56480d9ff3d3188970ee2b76527bd94a95567a42","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz","fileCount":24,"integrity":"sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==","signatures":[{"sig":"MEYCIQDhPWkUbc2LWTnPhTmGuNiBnQSAVoazhQSqp7Oo4kDuTwIhAKlk6wmDbJ1XKdsPaiEGf3P7/v77dpo6+3JR1Z8Ke2aJ","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":172011,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjZG7KACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqvCQ//Ua7lOYFJwFNt8ltN+PFAXHiJqet8O7P7FbYhpss6vLh8ExsW\r\nzgUsrRLdhrA+YE2js6Y2lkFvu7n6cHykedtQrq3MPW5JHrJ/0m3b6cC2tAdq\r\nfKh6+IeM4Y+MlXSd0x1USOB23nZyfy2PBLJmk6LoUbhaTE+7WO7NbqYnEokd\r\nZOf+7AR+yy2zCpgFTawYqtLYo9LFjj5UA2FBNj6O4mYwXW4kMjMs1UJkICWY\r\nY2ye1d/SEfQn2uLGG5k1hcVSQDb5Gsl3b8NFVgXH0qEV9MWrbMQZaUdaf8Ji\r\nJ0rW8rkNo4mctxN9TNJCbp5p6bGOxLrhfr0Njf19zyc2vl7zoDT0CNPijIip\r\nJ/UzyHP3d/ccQfJljMaUiw7gYZcLQFROYdP8ntk4hvwm8RiCtDjAs6ycX61w\r\ncFq4ABwhBGHqY4+F4VkS7FyZmH7d/ZFVoGr0CFEL51LbnxiXP32MMqI8ZJsV\r\nbJM+iMqJFNRHzW5+2iFzqaWYmGVlPLMPJ68LHH9y2EzjWM/JlLXUeSi+VicN\r\n4mRNL/yAfDHlbaU3CpTu54IJljZCdOYy5JBEqk7v2dRmEQRI9722cnE1+HbJ\r\nfmGe30tX0sRzwSlz7Mm7dHUALulSqFKvvr2MpmeX7VdBLqsctbqjqCmDIsGh\r\nw/EUKRNGBWD9WxaEyqJz5TFLHkbbIP5zSDg=\r\n=IdYF\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"scripts":{"lint":"eslint src test","test":"jest","build":"rimraf dist lib es && yarn build:types && yarn build:commonjs && yarn build:es && yarn build:umd && yarn build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es && cp src/versionedTypes/package.dist.json es/versionedTypes/package.json","test:cov":"jest --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","prepublishOnly":"yarn build","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"16.14.0","typesVersions":{"<4.2":{"*":["./src/legacyTypes/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","chai":"^4.3.4","jest":"^27.3.1","mocha":"^9.1.3","eslint":"^8.0.1","mkdirp":"^1.0.4","rimraf":"^3.0.2","rollup":"^2.58.0","tslint":"6.1.3","ts-jest":"27.0.7","prettier":"^2.7.1","coveralls":"^3.1.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","codecov.io":"^0.1.6","typescript":"4.8.3","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","react-redux":"^7.2.6","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@reduxjs/toolkit":"^1.9.0-rc.1","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","@microsoft/api-extractor":"^7.18.16","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.7_1667526345847_0.10590805186470997","host":"s3://npm-registry-packages"}},"4.1.8":{"name":"reselect","version":"4.1.8","keywords":["react","redux"],"license":"MIT","_id":"reselect@4.1.8","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"3f5dc671ea168dccdeb3e141236f69f02eaec524","tarball":"https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz","fileCount":24,"integrity":"sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==","signatures":[{"sig":"MEQCIHmS0b+F1vRJBtR3L1ni82/Mt2v1jN+oagucuMRDw8qwAiBPunRZsHLQqxwrbpudu+AjbYGK9Lxd7ltUeZLee79YNg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":174587,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkPFssACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp4sw//aVz6EiuSoxqFcY9EmoDbQ1Dh0c4KI9YHRce2i/9GmeSPj+IJ\r\n2T7B1MJkD0AABZBKn8lU+KOPZVk2tTUfH8hGQA0Oql19xblgpRq9kU16+tbN\r\n/9GAY4qpH54LbBX5mMW5rdIU2Zm1m6JVQYmqEt735FceTplWn14aN8nh39a2\r\nrRJza1uuZ0RXeYCNrHbzdX6i5/YPhBsYGj+XMV+8GMZDBHDAUSjjkiS5+zFH\r\nSAnoq6DHDrfCIyp5j8DoO+Zyz9c7rSR12hSKMaRXLXW/P+bwBc+k7havEUYA\r\nW7m93pUlCEUF350UkJJzJFtJeG5mtEhPZlPfJr5EAIg03KOyO6Fqx8xV0Vvq\r\nt6qdJjufODZ2i/sYCnCPxf4QuP803iQZwSIEQ/oCZtD18d8SN7Rk9ILySy3B\r\n1QvP0uf2UI6cASl1M5NgazN4+ytIrAg/Rc0lrFBRD8FhdmCGQ8YOLcee2VMO\r\nJk/K5OlmrJelnpT+HHnDLTG0PtW4CIwF0JFrRuelfbZ3BJR4uAuNRrsCbPC5\r\nj8sw8n/Z/PWfECizzVv6TlzNh3bQJiXw15gWhScMEQrwGdOkum3AICAZ86AE\r\nPQf9nf0Tw5nq92FVvLryRHOcBo5coV63fTsrSlFkoylnf7w/CtFvMzBjdseA\r\nz1H8xFElxs4NtZWIw6uyk3Tl9SAhx/48z+E=\r\n=QXoa\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./lib/index.js","types":"./es/index.d.ts","unpkg":"./dist/reselect.js","module":"./es/index.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"gitHead":"c3df23a545fa01482ceff3c6fff38942ecab946c","scripts":{"lint":"eslint src test","test":"vitest run","build":"rimraf dist lib es && yarn build:types && yarn build:commonjs && yarn build:es && yarn build:umd && yarn build:umd:min","clean":"rimraf lib dist es coverage","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","build:es":"babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es && cp src/versionedTypes/package.dist.json es/versionedTypes/package.json","test:cov":"vitest run --coverage","api-types":"api-extractor run --local","build:umd":"cross-env NODE_ENV=development rollup -c -o dist/reselect.js","build:types":"tsc","build:umd:min":"cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js","build:commonjs":"cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"9.5.0","description":"Selectors for Redux.","directories":{},"jsnext:main":"./es/index.js","sideEffects":false,"_nodeVersion":"18.15.0","typesVersions":{"<4.2":{"*":["./src/legacyTypes/ts4.1/index.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"ncp":"^2.0.0","nyc":"^15.1.0","jest":"^27.3.1","eslint":"^8.0.1","mkdirp":"^1.0.4","rimraf":"^3.0.2","rollup":"^2.58.0","tslint":"6.1.3","vitest":"^0.29.8","prettier":"^2.7.1","cross-env":"^7.0.3","@babel/cli":"^7.15.7","typescript":"^4.9","@babel/core":"^7.15.8","@types/jest":"^27.0.2","memoize-one":"^6.0.0","react-redux":"^7.2.6","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","lodash.memoize":"^4.1.2","@babel/register":"^7.15.3","@reduxjs/toolkit":"^1.9.3","@babel/preset-env":"^7.15.8","eslint-plugin-react":"^7.26.1","@rollup/plugin-babel":"^5.3.0","rollup-plugin-terser":"^7.0.2","@rollup/plugin-replace":"^3.0.0","@rollup/plugin-commonjs":"^21.0.1","@babel/preset-typescript":"^7.15.0","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@rollup/plugin-node-resolve":"^13.0.6","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_4.1.8_1681677100440_0.22678545179105924","host":"s3://npm-registry-packages"}},"5.0.0-alpha.0":{"name":"reselect","version":"5.0.0-alpha.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0-alpha.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"a0d5807fd43f856d4273dce87401a2d40111a958","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0-alpha.0.tgz","fileCount":21,"integrity":"sha512-v/t13mKs8jyKxd5Fin7nB2VX1j8MK2bTyEJ0rbhmkQF1m1DlPNY0UrEOP9MPEzKPgK5Hl8AXlrLrkr2/FnZHRQ==","signatures":[{"sig":"MEYCIQCWOmtOALJG0/7/8X091ccS8JZmahG+acfvUqCJ5mDRewIhAMzDd5l8Xk/Yp27lUCcpbdRhHZWnyhMVCubqeBac/fxE","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":104822},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.mjs","readme":"# Reselect\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to Redux, it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```js\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Basic Usage\r\n\r\nReselect exports a `createSelector` API, which generates memoized selector functions. `createSelector` accepts one or more \"input\" selectors, which extract values from arguments, and an \"output\" selector that receives the extracted values and should return a derived value. If the generated selector is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/objective-waterfall-1z5y8?file=/src/index.js):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  selectTax,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n  - [Redux Toolkit](#redux-toolkit)\r\n  - [Standalone](#standalone)\r\n- [Basic Usage](#basic-usage)\r\n- [API](#api)\r\n  - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n  - [defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck)\r\n  - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n    - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n    - [Use memoize function from Lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n  - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [FAQ](#faq)\r\n  - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n  - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n- [Related Projects](#related-projects)\r\n  - [re-reselect](#re-reselect)\r\n  - [reselect-tools](#reselect-tools)\r\n  - [reselect-debugger](#reselect-debugger)\r\n- [License](#license)\r\n- [Prior Art and Inspiration](#prior-art-and-inspiration)\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nAccepts one or more \"input selectors\" (either as separate arguments or a single array), a single \"output selector\" / \"result function\", and an optional options object, and generates a memoized selector function.\r\n\r\nWhen the selector is called, each input selector will be called with all of the provided arguments. The extracted values are then passed as separate arguments to the output selector, which should calculate and return a final result. The inputs and result are cached for later use.\r\n\r\nIf the selector is called again with the same arguments, the previously cached result is returned instead of recalculating a new result.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // New in 4.1: Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nSelectors are typically called with a Redux `state` value as the first argument, and the input selectors extract pieces of the `state` object for use in calculations. However, it's also common to want to pass additional arguments, such as a value to filter by. Since input selectors are given all arguments, they can extract the additional arguments and pass them to the output selector:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the standard memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (new in 4.1).\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\nAs of Reselect 4.1, `defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from Lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It can be used with any plain JS data, such as typical React state values, as long as that data is being updated immutably.\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nAs shown in the API reference section above, provide input selectors that extract the arguments and forward them to the output selector for calculation:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Yes, although it requires some planning.\r\n\r\nAs of Reselect 4.1, you can create a selector with a cache size greater than one by passing in a `maxSize` option under `memoizeOptions` for use with the built-in `defaultMemoize`.\r\n\r\nOtherwise, selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. This can be called in a React component inside the `useMemo` hook to generate a unique selector instance per component.\r\n- Create a custom selector with a cache size greater than one using `createSelectorCreator`\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`\r\n\r\nA: This can often occur with deeply recursive types, which occur in this library. Please see [this\r\ncomment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as\r\nrelating to nested selectors.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Prior Art and Inspiration\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"902f3257666e697e692e01af5e7ab6ed8ece665a","scripts":{"lint":"eslint src test","test":"vitest run","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"16.14.0","typesVersions":{"<=4.6":{"*":["./dist/versionedTypes/ts46/index.d.ts"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^6.7.0","eslint":"^8.0.1","rimraf":"^3.0.2","vitest":"^0.29.8","shelljs":"^0.8.5","prettier":"^2.7.1","typescript":"^4.9","memoize-one":"^6.0.0","react-redux":"^8.0.2","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^1.9.3","eslint-plugin-react":"^7.26.1","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0-alpha.0_1683685671286_0.08275195047145467","host":"s3://npm-registry-packages"}},"5.0.0-alpha.1":{"name":"reselect","version":"5.0.0-alpha.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0-alpha.1","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"254f6bb6369a276e4f6b4d88824cbd699ca57a70","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0-alpha.1.tgz","fileCount":33,"integrity":"sha512-RJtLisqUjNBYqKQzkxWDi8LIMxZYtbekfKqkFn+FWJt9HLNbJzBQrYh6T6IVnEEdJ6XiNoEPm8aMh65ZTD8mYQ==","signatures":[{"sig":"MEYCIQDacce9+jVSUxAuv9Udw1KziXcv1Jas0aCa1nL1l9IORwIhAIKOelnvZbocC4Ovw3AadFXp/fPTB+8zp6U4OHlB6kpC","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":153320},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.mjs","readme":"# Reselect\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to Redux, it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```js\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Basic Usage\r\n\r\nReselect exports a `createSelector` API, which generates memoized selector functions. `createSelector` accepts one or more \"input\" selectors, which extract values from arguments, and an \"output\" selector that receives the extracted values and should return a derived value. If the generated selector is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/objective-waterfall-1z5y8?file=/src/index.js):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  selectTax,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n  - [Redux Toolkit](#redux-toolkit)\r\n  - [Standalone](#standalone)\r\n- [Basic Usage](#basic-usage)\r\n- [API](#api)\r\n  - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n  - [defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck)\r\n  - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n    - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n    - [Use memoize function from Lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n  - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [FAQ](#faq)\r\n  - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n  - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n- [Related Projects](#related-projects)\r\n  - [re-reselect](#re-reselect)\r\n  - [reselect-tools](#reselect-tools)\r\n  - [reselect-debugger](#reselect-debugger)\r\n- [License](#license)\r\n- [Prior Art and Inspiration](#prior-art-and-inspiration)\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nAccepts one or more \"input selectors\" (either as separate arguments or a single array), a single \"output selector\" / \"result function\", and an optional options object, and generates a memoized selector function.\r\n\r\nWhen the selector is called, each input selector will be called with all of the provided arguments. The extracted values are then passed as separate arguments to the output selector, which should calculate and return a final result. The inputs and result are cached for later use.\r\n\r\nIf the selector is called again with the same arguments, the previously cached result is returned instead of recalculating a new result.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // New in 4.1: Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nSelectors are typically called with a Redux `state` value as the first argument, and the input selectors extract pieces of the `state` object for use in calculations. However, it's also common to want to pass additional arguments, such as a value to filter by. Since input selectors are given all arguments, they can extract the additional arguments and pass them to the output selector:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the standard memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (new in 4.1).\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\nAs of Reselect 4.1, `defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from Lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It can be used with any plain JS data, such as typical React state values, as long as that data is being updated immutably.\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nAs shown in the API reference section above, provide input selectors that extract the arguments and forward them to the output selector for calculation:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Yes, although it requires some planning.\r\n\r\nAs of Reselect 4.1, you can create a selector with a cache size greater than one by passing in a `maxSize` option under `memoizeOptions` for use with the built-in `defaultMemoize`.\r\n\r\nOtherwise, selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. This can be called in a React component inside the `useMemo` hook to generate a unique selector instance per component.\r\n- Create a custom selector with a cache size greater than one using `createSelectorCreator`\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`\r\n\r\nA: This can often occur with deeply recursive types, which occur in this library. Please see [this\r\ncomment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as\r\nrelating to nested selectors.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Prior Art and Inspiration\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"ee383b0a80129a3906c31392af75973e9cd23a7e","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"16.14.0","typesVersions":{"<=4.6":{"*":["./dist/versionedTypes/ts46/index.d.ts"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^6.7.0","eslint":"^8.0.1","rimraf":"^3.0.2","vitest":"^0.29.8","shelljs":"^0.8.5","prettier":"^2.7.1","typescript":"^4.9","memoize-one":"^6.0.0","react-redux":"^8.0.2","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^1.9.3","eslint-plugin-react":"^7.26.1","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0-alpha.1_1683690108449_0.6422495031699875","host":"s3://npm-registry-packages"}},"5.0.0-alpha.2":{"name":"reselect","version":"5.0.0-alpha.2","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0-alpha.2","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"threehams","email":"threehams@gmail.com"},{"name":"faassen","email":"faassen@startifact.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"alex3165","email":"alexr.3165@gmail.com"},{"name":"acemarke","email":"mark.erikson@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"1a0272da0debb7f980b5e83d9a6dec4ba04aad01","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0-alpha.2.tgz","fileCount":38,"integrity":"sha512-wachIH1FWB/ceIgBP418PXtjJyhvgjtjqi0Go5nCqe/2xrwwAyCn1/4krfBurNfxxo7dWpiLGb1yYjCrWi40PA==","signatures":[{"sig":"MEYCIQDxlw59MZuZNNRi1nEynVS3gHPRHahbnI2/8MkM0RM/7wIhALaPUU4VCpZRv072PHT3y++j1FRv6ziSLnLjma1r/FPE","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":346178},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","readme":"# Reselect\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to Redux, it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```js\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Basic Usage\r\n\r\nReselect exports a `createSelector` API, which generates memoized selector functions. `createSelector` accepts one or more \"input\" selectors, which extract values from arguments, and an \"output\" selector that receives the extracted values and should return a derived value. If the generated selector is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/objective-waterfall-1z5y8?file=/src/index.js):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  selectTax,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n  - [Redux Toolkit](#redux-toolkit)\r\n  - [Standalone](#standalone)\r\n- [Basic Usage](#basic-usage)\r\n- [API](#api)\r\n  - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n  - [defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck)\r\n  - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n    - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n    - [Use memoize function from Lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n  - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [Development-only checks](#development-only-checks)\r\n  - [`inputStabilityCheck`](#inputstabilitycheck)\r\n    - [Global configuration](#global-configuration)\r\n    - [Per-selector configuration](#per-selector-configuration)\r\n- [FAQ](#faq)\r\n  - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n  - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n- [Related Projects](#related-projects)\r\n  - [re-reselect](#re-reselect)\r\n  - [reselect-tools](#reselect-tools)\r\n  - [reselect-debugger](#reselect-debugger)\r\n- [License](#license)\r\n- [Prior Art and Inspiration](#prior-art-and-inspiration)\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nAccepts one or more \"input selectors\" (either as separate arguments or a single array), a single \"output selector\" / \"result function\", and an optional options object, and generates a memoized selector function.\r\n\r\nWhen the selector is called, each input selector will be called with all of the provided arguments. The extracted values are then passed as separate arguments to the output selector, which should calculate and return a final result. The inputs and result are cached for later use.\r\n\r\nIf the selector is called again with the same arguments, the previously cached result is returned instead of recalculating a new result.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // New in 4.1: Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nSelectors are typically called with a Redux `state` value as the first argument, and the input selectors extract pieces of the `state` object for use in calculations. However, it's also common to want to pass additional arguments, such as a value to filter by. Since input selectors are given all arguments, they can extract the additional arguments and pass them to the output selector:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the standard memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (new in 4.1).\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\nAs of Reselect 4.1, `defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from Lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## Development-only checks\r\n\r\n### `inputStabilityCheck`\r\n\r\nIn development, an extra check is conducted on your input selectors. It runs your input selectors an extra time with the same parameters, and warns in console if they return a different result (based on your `memoize` method).\r\n\r\nThis is important, as an input selector returning a materially different result with the same parameters means that the output selector will be run unnecessarily, thus (potentially) creating a new result and causing rerenders.\r\n\r\n```js\r\nconst addNumbers = createSelector(\r\n  // this input selector will always return a new reference when run\r\n  // so cache will never be used\r\n  (a, b) => ({ a, b }),\r\n  ({ a, b }) => ({ total: a + b })\r\n)\r\n// instead, you should have an input selector for each stable piece of data\r\nconst addNumbersStable = createSelector(\r\n  (a, b) => a,\r\n  (a, b) => b,\r\n  (a, b) => ({\r\n    total: a + b\r\n  })\r\n)\r\n```\r\n\r\nBy default, this will only happen when the selector is first called. You can configure the check globally or per selector, to change it to always run when the selector is called, or to never run.\r\n\r\n_This check is disabled for production environments._\r\n\r\n#### Global configuration\r\n\r\nA `setInputStabilityCheckEnabled` function is exported from `reselect`, which should be called with the desired setting.\r\n\r\n```js\r\nimport { setInputStabilityCheckEnabled } from 'reselect'\r\n\r\n// run when selector is first called (default)\r\nsetInputStabilityCheckEnabled('once')\r\n\r\n// always run\r\nsetInputStabilityCheckEnabled(true)\r\n\r\n// never run\r\nsetInputStabilityCheckEnabled(false)\r\n```\r\n\r\n#### Per-selector configuration\r\n\r\nA value can be passed as part of the selector options object, which will override the global setting for the given selector.\r\n\r\n```ts\r\nconst selectPersonName = createSelector(\r\n  selectPerson,\r\n  person => person.firstName + ' ' + person.lastName,\r\n  // `inputStabilityCheck` accepts the same settings\r\n  // as `setInputStabilityCheckEnabled`\r\n  { inputStabilityCheck: false }\r\n)\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It can be used with any plain JS data, such as typical React state values, as long as that data is being updated immutably.\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nAs shown in the API reference section above, provide input selectors that extract the arguments and forward them to the output selector for calculation:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Yes, although it requires some planning.\r\n\r\nAs of Reselect 4.1, you can create a selector with a cache size greater than one by passing in a `maxSize` option under `memoizeOptions` for use with the built-in `defaultMemoize`.\r\n\r\nOtherwise, selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. This can be called in a React component inside the `useMemo` hook to generate a unique selector instance per component.\r\n- Create a custom selector with a cache size greater than one using `createSelectorCreator`\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`\r\n\r\nA: This can often occur with deeply recursive types, which occur in this library. Please see [this\r\ncomment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as\r\nrelating to nested selectors.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Prior Art and Inspiration\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"88c46381c61f3c2117f990a5aace3dbe228bd0ff","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"16.14.0","typesVersions":{"<=4.6":{"*":["./dist/versionedTypes/ts46/index.d.ts"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^6.7.0","react":"^18.2.0","eslint":"^8.0.1","rimraf":"^3.0.2","vitest":"^0.29.8","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"^4.9","memoize-one":"^6.0.0","react-redux":"^8.0.2","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^1.9.3","eslint-plugin-react":"^7.26.1","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0-alpha.2_1684103308841_0.18670158253263924","host":"s3://npm-registry-packages"}},"5.0.0-beta.0":{"name":"reselect","version":"5.0.0-beta.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0-beta.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"04f1eabdaccad5815bd8e1ce73c8307013b3ba08","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0-beta.0.tgz","fileCount":26,"integrity":"sha512-q9cwinGYNn3xNtyknjmNZQvH6FYdxS0tqUin1MIrtMLt1QB17FFz/C2WhlPgYBYuKJe9K/+bTKALuYXn+Elp1g==","signatures":[{"sig":"MEUCIEHJNTSeK/Q4kzT5Nhzl3mrNHKJJ3tH4aztUFJtDTftrAiEAzYOstkrU//wjwOpA06ETVMX3h/TncJqMZGq64I+s8N8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":443563},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","readme":"# Reselect\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to Redux, it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```js\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Basic Usage\r\n\r\nReselect exports a `createSelector` API, which generates memoized selector functions. `createSelector` accepts one or more \"input\" selectors, which extract values from arguments, and an \"output\" selector that receives the extracted values and should return a derived value. If the generated selector is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/objective-waterfall-1z5y8?file=/src/index.js):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  selectTax,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n  - [Redux Toolkit](#redux-toolkit)\r\n  - [Standalone](#standalone)\r\n- [Basic Usage](#basic-usage)\r\n- [API](#api)\r\n  - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n  - [defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck)\r\n  - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n    - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n    - [Use memoize function from Lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n  - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [Development-only checks](#development-only-checks)\r\n  - [`inputStabilityCheck`](#inputstabilitycheck)\r\n    - [Global configuration](#global-configuration)\r\n    - [Per-selector configuration](#per-selector-configuration)\r\n- [FAQ](#faq)\r\n  - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n  - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n- [Related Projects](#related-projects)\r\n  - [re-reselect](#re-reselect)\r\n  - [reselect-tools](#reselect-tools)\r\n  - [reselect-debugger](#reselect-debugger)\r\n- [License](#license)\r\n- [Prior Art and Inspiration](#prior-art-and-inspiration)\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nAccepts one or more \"input selectors\" (either as separate arguments or a single array), a single \"output selector\" / \"result function\", and an optional options object, and generates a memoized selector function.\r\n\r\nWhen the selector is called, each input selector will be called with all of the provided arguments. The extracted values are then passed as separate arguments to the output selector, which should calculate and return a final result. The inputs and result are cached for later use.\r\n\r\nIf the selector is called again with the same arguments, the previously cached result is returned instead of recalculating a new result.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // New in 4.1: Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nSelectors are typically called with a Redux `state` value as the first argument, and the input selectors extract pieces of the `state` object for use in calculations. However, it's also common to want to pass additional arguments, such as a value to filter by. Since input selectors are given all arguments, they can extract the additional arguments and pass them to the output selector:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the standard memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (new in 4.1).\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\nAs of Reselect 4.1, `defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from Lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## Development-only checks\r\n\r\n### `inputStabilityCheck`\r\n\r\nIn development, an extra check is conducted on your input selectors. It runs your input selectors an extra time with the same parameters, and warns in console if they return a different result (based on your `memoize` method).\r\n\r\nThis is important, as an input selector returning a materially different result with the same parameters means that the output selector will be run unnecessarily, thus (potentially) creating a new result and causing rerenders.\r\n\r\n```js\r\nconst addNumbers = createSelector(\r\n  // this input selector will always return a new reference when run\r\n  // so cache will never be used\r\n  (a, b) => ({ a, b }),\r\n  ({ a, b }) => ({ total: a + b })\r\n)\r\n// instead, you should have an input selector for each stable piece of data\r\nconst addNumbersStable = createSelector(\r\n  (a, b) => a,\r\n  (a, b) => b,\r\n  (a, b) => ({\r\n    total: a + b\r\n  })\r\n)\r\n```\r\n\r\nBy default, this will only happen when the selector is first called. You can configure the check globally or per selector, to change it to always run when the selector is called, or to never run.\r\n\r\n_This check is disabled for production environments._\r\n\r\n#### Global configuration\r\n\r\nA `setInputStabilityCheckEnabled` function is exported from `reselect`, which should be called with the desired setting.\r\n\r\n```js\r\nimport { setInputStabilityCheckEnabled } from 'reselect'\r\n\r\n// run when selector is first called (default)\r\nsetInputStabilityCheckEnabled('once')\r\n\r\n// always run\r\nsetInputStabilityCheckEnabled('always')\r\n\r\n// never run\r\nsetInputStabilityCheckEnabled('never')\r\n```\r\n\r\n#### Per-selector configuration\r\n\r\nA value can be passed as part of the selector options object, which will override the global setting for the given selector.\r\n\r\n```ts\r\nconst selectPersonName = createSelector(\r\n  selectPerson,\r\n  person => person.firstName + ' ' + person.lastName,\r\n  // `inputStabilityCheck` accepts the same settings\r\n  // as `setInputStabilityCheckEnabled`\r\n  { inputStabilityCheck: 'never' }\r\n)\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It can be used with any plain JS data, such as typical React state values, as long as that data is being updated immutably.\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nAs shown in the API reference section above, provide input selectors that extract the arguments and forward them to the output selector for calculation:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Yes, although it requires some planning.\r\n\r\nAs of Reselect 4.1, you can create a selector with a cache size greater than one by passing in a `maxSize` option under `memoizeOptions` for use with the built-in `defaultMemoize`.\r\n\r\nOtherwise, selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. This can be called in a React component inside the `useMemo` hook to generate a unique selector instance per component.\r\n- Create a custom selector with a cache size greater than one using `createSelectorCreator`\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`\r\n\r\nA: This can often occur with deeply recursive types, which occur in this library. Please see [this\r\ncomment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as\r\nrelating to nested selectors.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Prior Art and Inspiration\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"77b946c0c7649f25c237a125b1c6c0f855a52a2d","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"16.14.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^6.7.0","react":"^18.2.0","eslint":"^8.0.1","rimraf":"^3.0.2","vitest":"^0.34","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"^4.9","memoize-one":"^6.0.0","react-redux":"^8.0.2","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^1.9.3","eslint-plugin-react":"^7.26.1","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0-beta.0_1698525582142_0.1236477831200804","host":"s3://npm-registry-packages"}},"5.0.0-beta.1":{"name":"reselect","version":"5.0.0-beta.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0-beta.1","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"8ab1882bad3a2d264eea67c0891150fc826bbef2","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0-beta.1.tgz","fileCount":26,"integrity":"sha512-DxH9DLLbaiuLI4gCM8kSfonXtqd9Lh1BsNQhZByr3pHb3c75eFfgxb4vNJxeTgHFn27aLlt3tX0Xh+IqvJsyuw==","signatures":[{"sig":"MEYCIQCZWMrZBNbWWOxI2kJvBCTXnhd5OzYGh2Bsj4uZs9WNIAIhAI15tXKR82oV0rsV2glSzUZc02YLUjbOuTOEqZetqNIt","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":544233},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","readme":"# Reselect\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing Redux to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.\r\n\r\n[![GitHub Workflow Status][build-badge]][build]\r\n[![npm package][npm-badge]][npm]\r\n[![Coveralls][coveralls-badge]][coveralls]\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to Redux, it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```js\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\nnpm install reselect\r\n\r\nyarn add reselect\r\n```\r\n\r\n## Basic Usage\r\n\r\nReselect exports a `createSelector` API, which generates memoized selector functions. `createSelector` accepts one or more \"input\" selectors, which extract values from arguments, and an \"output\" selector that receives the extracted values and should return a derived value. If the generated selector is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/objective-waterfall-1z5y8?file=/src/index.js):\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectShopItems = state => state.shop.items\r\nconst selectTaxPercent = state => state.shop.taxPercent\r\n\r\nconst selectSubtotal = createSelector(selectShopItems, items =>\r\n  items.reduce((subtotal, item) => subtotal + item.value, 0)\r\n)\r\n\r\nconst selectTax = createSelector(\r\n  selectSubtotal,\r\n  selectTaxPercent,\r\n  (subtotal, taxPercent) => subtotal * (taxPercent / 100)\r\n)\r\n\r\nconst selectTotal = createSelector(\r\n  selectSubtotal,\r\n  selectTax,\r\n  (subtotal, tax) => ({ total: subtotal + tax })\r\n)\r\n\r\nconst exampleState = {\r\n  shop: {\r\n    taxPercent: 8,\r\n    items: [\r\n      { name: 'apple', value: 1.2 },\r\n      { name: 'orange', value: 0.95 }\r\n    ]\r\n  }\r\n}\r\n\r\nconsole.log(selectSubtotal(exampleState)) // 2.15\r\nconsole.log(selectTax(exampleState)) // 0.172\r\nconsole.log(selectTotal(exampleState)) // { total: 2.322 }\r\n```\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n  - [Redux Toolkit](#redux-toolkit)\r\n  - [Standalone](#standalone)\r\n- [Basic Usage](#basic-usage)\r\n- [API](#api)\r\n  - [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)\r\n  - [defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck)\r\n  - [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)\r\n    - [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)\r\n    - [Use memoize function from Lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)\r\n  - [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)\r\n- [Development-only checks](#development-only-checks)\r\n  - [`inputStabilityCheck`](#inputstabilitycheck)\r\n    - [Global configuration](#global-configuration)\r\n    - [Per-selector configuration](#per-selector-configuration)\r\n- [FAQ](#faq)\r\n  - [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)\r\n  - [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)\r\n  - [Q: How do I test a selector?](#q-how-do-i-test-a-selector)\r\n  - [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)\r\n  - [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)\r\n- [Related Projects](#related-projects)\r\n  - [re-reselect](#re-reselect)\r\n  - [reselect-tools](#reselect-tools)\r\n  - [reselect-debugger](#reselect-debugger)\r\n- [License](#license)\r\n- [Prior Art and Inspiration](#prior-art-and-inspiration)\r\n\r\n## API\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)\r\n\r\nAccepts one or more \"input selectors\" (either as separate arguments or a single array), a single \"output selector\" / \"result function\", and an optional options object, and generates a memoized selector function.\r\n\r\nWhen the selector is called, each input selector will be called with all of the provided arguments. The extracted values are then passed as separate arguments to the output selector, which should calculate and return a final result. The inputs and result are cached for later use.\r\n\r\nIf the selector is called again with the same arguments, the previously cached result is returned instead of recalculating a new result.\r\n\r\n`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.\r\n\r\nBy default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .\r\n\r\n```js\r\nconst selectValue = createSelector(\r\n  state => state.values.value1,\r\n  state => state.values.value2,\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// You can also pass an array of selectors\r\nconst selectTotal = createSelector(\r\n  [state => state.values.value1, state => state.values.value2],\r\n  (value1, value2) => value1 + value2\r\n)\r\n\r\n// Selector behavior can be customized\r\nconst customizedSelector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => a + b,\r\n  {\r\n    // New in 4.1: Pass options through to the built-in `defaultMemoize` function\r\n    memoizeOptions: {\r\n      equalityCheck: (a, b) => a === b,\r\n      maxSize: 10,\r\n      resultEqualityCheck: shallowEqual\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nSelectors are typically called with a Redux `state` value as the first argument, and the input selectors extract pieces of the `state` object for use in calculations. However, it's also common to want to pass additional arguments, such as a value to filter by. Since input selectors are given all arguments, they can extract the additional arguments and pass them to the output selector:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n`defaultMemoize` memoizes the function passed in the func parameter. It is the standard memoize function used by `createSelector`.\r\n\r\n`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (new in 4.1).\r\n\r\n`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:\r\n\r\n```js\r\nfunction defaultEqualityCheck(previousVal, currentVal) {\r\n  return currentVal === previousVal\r\n}\r\n```\r\n\r\nAs of Reselect 4.1, `defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:\r\n\r\n```ts\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\nAvailable options are:\r\n\r\n- `equalityCheck`: used to compare the individual arguments of the provided calculation function\r\n- `resultEqualityCheck`: if provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.\r\n- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally\r\n\r\nThe returned memoized function will have a `.clearCache()` method attached.\r\n\r\n`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.\r\n\r\n### createSelectorCreator(memoize, ...memoizeOptions)\r\n\r\n`createSelectorCreator` can be used to make a customized version of `createSelector`.\r\n\r\nThe `memoize` argument is a memoization function to replace `defaultMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```js\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // function to be used to memoize resultFunc\r\n  option1, // option1 will be passed as second argument to customMemoize\r\n  option2, // option2 will be passed as third argument to customMemoize\r\n  option3 // option3 will be passed as fourth argument to customMemoize\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  input1,\r\n  input2,\r\n  resultFunc // resultFunc will be passed as first argument to customMemoize\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```js\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\nHere are some examples of how you might use `createSelectorCreator`:\r\n\r\n#### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  state => state.values.filter(val => val < 5),\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n#### Use memoize function from Lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nlet called = 0\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\nconst selector = customSelectorCreator(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => {\r\n    called++\r\n    return a + b\r\n  }\r\n)\r\n```\r\n\r\n### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)\r\n\r\n`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.\r\n\r\n```js\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```js\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n## Development-only checks\r\n\r\n### `inputStabilityCheck`\r\n\r\nIn development, an extra check is conducted on your input selectors. It runs your input selectors an extra time with the same parameters, and warns in console if they return a different result (based on your `memoize` method).\r\n\r\nThis is important, as an input selector returning a materially different result with the same parameters means that the output selector will be run unnecessarily, thus (potentially) creating a new result and causing rerenders.\r\n\r\n```js\r\nconst addNumbers = createSelector(\r\n  // this input selector will always return a new reference when run\r\n  // so cache will never be used\r\n  (a, b) => ({ a, b }),\r\n  ({ a, b }) => ({ total: a + b })\r\n)\r\n// instead, you should have an input selector for each stable piece of data\r\nconst addNumbersStable = createSelector(\r\n  (a, b) => a,\r\n  (a, b) => b,\r\n  (a, b) => ({\r\n    total: a + b\r\n  })\r\n)\r\n```\r\n\r\nBy default, this will only happen when the selector is first called. You can configure the check globally or per selector, to change it to always run when the selector is called, or to never run.\r\n\r\n_This check is disabled for production environments._\r\n\r\n#### Global configuration\r\n\r\nA `setInputStabilityCheckEnabled` function is exported from `reselect`, which should be called with the desired setting.\r\n\r\n```js\r\nimport { setInputStabilityCheckEnabled } from 'reselect'\r\n\r\n// run when selector is first called (default)\r\nsetInputStabilityCheckEnabled('once')\r\n\r\n// always run\r\nsetInputStabilityCheckEnabled('always')\r\n\r\n// never run\r\nsetInputStabilityCheckEnabled('never')\r\n```\r\n\r\n#### Per-selector configuration\r\n\r\nA value can be passed as part of the selector options object, which will override the global setting for the given selector.\r\n\r\n```ts\r\nconst selectPersonName = createSelector(\r\n  selectPerson,\r\n  person => person.firstName + ' ' + person.lastName,\r\n  // `inputStabilityCheck` accepts the same settings\r\n  // as `setInputStabilityCheckEnabled`\r\n  { inputStabilityCheck: 'never' }\r\n)\r\n```\r\n\r\n## FAQ\r\n\r\n### Q: Why isn’t my selector recomputing when the input state changes?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\nThe following example defines a simple selector that determines if the first todo item in an array of todos has been completed:\r\n\r\n```js\r\nconst selectIsFirstTodoComplete = createSelector(\r\n  state => state.todos[0],\r\n  todo => todo && todo.completed\r\n)\r\n```\r\n\r\nThe following state update function **will not** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // BAD: mutating an existing object\r\n      return state.map(todo => {\r\n        todo.completed = !areAllMarked\r\n        return todo\r\n      })\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following state update function **will** work with `selectIsFirstTodoComplete`:\r\n\r\n```js\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case COMPLETE_ALL:\r\n      const areAllMarked = state.every(todo => todo.completed)\r\n      // GOOD: returning a new object each time with Object.assign\r\n      return state.map(todo =>\r\n        Object.assign({}, todo, {\r\n          completed: !areAllMarked\r\n        })\r\n      )\r\n\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nIf you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.\r\n\r\n### Q: Why is my selector recomputing when the input state stays the same?\r\n\r\nA: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      return state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nThe following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.\r\n\r\n```js\r\nimport { createSelector } from 'reselect'\r\n\r\nconst todosSelector = state => state.todos\r\n\r\nexport const selectVisibleTodos = createSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nYou can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:\r\n\r\n```js\r\nimport { REMOVE_OLD } from '../constants/ActionTypes'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst initialState = [\r\n  {\r\n    text: 'Use Redux',\r\n    completed: false,\r\n    id: 0,\r\n    timestamp: Date.now()\r\n  }\r\n]\r\n\r\nexport default function todos(state = initialState, action) {\r\n  switch (action.type) {\r\n    case REMOVE_OLD:\r\n      const updatedState = state.filter(todo => {\r\n        return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()\r\n      })\r\n      return isEqual(updatedState, state) ? state : updatedState\r\n    default:\r\n      return state\r\n  }\r\n}\r\n```\r\n\r\nAlternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\nconst selectTodos = state => state.todos\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(\r\n  defaultMemoize,\r\n  isEqual\r\n)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst mySelector = createDeepEqualSelector(\r\n  todosSelector,\r\n  (todos) => {\r\n    ...\r\n  }\r\n)\r\n```\r\n\r\nAlways check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.\r\n\r\n### Q: Can I use Reselect without Redux?\r\n\r\nA: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It can be used with any plain JS data, such as typical React state values, as long as that data is being updated immutably.\r\n\r\n### Q: How do I create a selector that takes an argument?\r\n\r\nConceptually, Reselect works like this internally:\r\n\r\n```ts\r\nconst finalSelector = (...args) => {\r\n  const extractedValues = inputFunctions.map(input => input(...args));\r\n  return output(...extractedValues);\r\n}\r\n```\r\n\r\nIn other words, all the arguments passed to the selector function are immediately passed to all of the inputs.\r\n\r\nAs shown in the API reference section above, provide input selectors that extract the arguments and forward them to the output selector for calculation:\r\n\r\n```js\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    // Usual first input - extract value from `state`\r\n    state => state.items,\r\n    // Take the second arg, `category`, and forward to the output selector\r\n    (state, category) => category\r\n  ],\r\n  // Output selector gets (`items, category)` as args\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n```\r\n\r\n\r\nMore generally, you can have N arguments passed to the selector, and you can have M input functions extracting values from any of those arguments.  All M extracted values get passed to the output function.\r\n\r\n### Q: The default memoization function is no good, can I use a different one?\r\n\r\nA: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### Q: How do I test a selector?\r\n\r\nA: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.\r\n\r\n```js\r\nconst selector = createSelector(\r\n  state => state.a,\r\n  state => state.b,\r\n  (a, b) => ({\r\n    c: a * 2,\r\n    d: b * 3\r\n  })\r\n)\r\n\r\ntest('selector unit test', () => {\r\n  assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })\r\n  assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })\r\n})\r\n```\r\n\r\nIt may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:\r\n\r\n```js\r\nsuite('selector', () => {\r\n  let state = { a: 1, b: 2 }\r\n\r\n  const reducer = (state, action) => ({\r\n    a: action(state.a),\r\n    b: action(state.b)\r\n  })\r\n\r\n  const selector = createSelector(\r\n    state => state.a,\r\n    state => state.b,\r\n    (a, b) => ({\r\n      c: a * 2,\r\n      d: b * 3\r\n    })\r\n  )\r\n\r\n  const plusOne = x => x + 1\r\n  const id = x => x\r\n\r\n  test('selector unit test', () => {\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    state = reducer(state, id)\r\n    assert.deepEqual(selector(state), { c: 4, d: 9 })\r\n    assert.equal(selector.recomputations(), 1)\r\n    state = reducer(state, plusOne)\r\n    assert.deepEqual(selector(state), { c: 6, d: 12 })\r\n    assert.equal(selector.recomputations(), 2)\r\n  })\r\n})\r\n```\r\n\r\nAdditionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.\r\n\r\nFor example if you have a set of selectors like this:\r\n\r\n**selectors.js**\r\n\r\n```js\r\nexport const selectFirst = createSelector( ... )\r\nexport const selectSecond = createSelector( ... )\r\nexport const selectThird = createSelector( ... )\r\n\r\nexport const myComposedSelector = createSelector(\r\n  selectFirst,\r\n  selectSecond,\r\n  selectThird,\r\n  (first, second, third) => first * second < third\r\n)\r\n```\r\n\r\nAnd then a set of unit tests like this:\r\n\r\n**test/selectors.js**\r\n\r\n```js\r\n// tests for the first three selectors...\r\ntest(\"selectFirst unit test\", () => { ... })\r\ntest(\"selectSecond unit test\", () => { ... })\r\ntest(\"selectThird unit test\", () => { ... })\r\n\r\n// We have already tested the previous\r\n// three selector outputs so we can just call `.resultFunc`\r\n// with the values we want to test directly:\r\ntest(\"myComposedSelector unit test\", () => {\r\n  // here instead of calling selector()\r\n  // we just call selector.resultFunc()\r\n  assert(myComposedSelector.resultFunc(1, 2, 3), true)\r\n  assert(myComposedSelector.resultFunc(2, 2, 1), false)\r\n})\r\n```\r\n\r\nFinally, each selector has a `resetRecomputations` method that sets\r\nrecomputations back to 0. The intended use is for a complex selector that may\r\nhave many independent tests and you don't want to manually manage the\r\ncomputation count or create a \"dummy\" selector for each test.\r\n\r\n### Q: Can I share a selector across multiple component instances?\r\n\r\nA: Yes, although it requires some planning.\r\n\r\nAs of Reselect 4.1, you can create a selector with a cache size greater than one by passing in a `maxSize` option under `memoizeOptions` for use with the built-in `defaultMemoize`.\r\n\r\nOtherwise, selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:\r\n\r\n- Create a factory function which returns a new selector for each instance of the component. This can be called in a React component inside the `useMemo` hook to generate a unique selector instance per component.\r\n- Create a custom selector with a cache size greater than one using `createSelectorCreator`\r\n\r\n### Q: Are there TypeScript Typings?\r\n\r\nA: Yes! Reselect is now written in TS itself, so they should Just Work™.\r\n\r\n### Q: I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`\r\n\r\nA: This can often occur with deeply recursive types, which occur in this library. Please see [this\r\ncomment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as\r\nrelating to nested selectors.\r\n\r\n### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nA: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Prior Art and Inspiration\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"9966bf2ae3d69e7a922ce448a86fc636cecb8fc9","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","bench":"vitest --run bench","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"16.14.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^6.7.0","react":"^18.2.0","eslint":"^8.0.1","rimraf":"^3.0.2","vitest":"^0.34","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"^4.9","memoize-one":"^6.0.0","react-redux":"^8.0.2","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^1.9.3","eslint-plugin-react":"^7.26.1","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"5.1.0","@typescript-eslint/eslint-plugin":"5.1.0","@typescript-eslint/eslint-plugin-tslint":"5.1.0"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0-beta.1_1700108874604_0.4866013646366181","host":"s3://npm-registry-packages"}},"5.0.0-rc.0":{"name":"reselect","version":"5.0.0-rc.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0-rc.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"7563cfcf26850cbe4f8a47e0fe76754b983c582a","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0-rc.0.tgz","fileCount":29,"integrity":"sha512-SEFZMpPuyC4M0ThG709V2Tpq9YWlDq2ubyfq7XSRRU9ONje6VykUoYUlWKISl1BWmfBLuRYkDS2mg5r2nu1jBA==","signatures":[{"sig":"MEYCIQDS3IOqFXlvOHxDEd+3YXNuy2vp1G2FUn05cL2ndrJ/xwIhAPm1WOE97DEkJYRJm/bNmlASSBlLuXtDnOP6n6FYfAUk","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":646834},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","readme":"# Reselect\r\n\r\n[![npm package][npm-badge]][npm][![Coveralls][coveralls-badge]][coveralls][![GitHub Workflow Status][build-badge]][build]![TypeScript][typescript-badge]\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing [Redux] to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with [React-Redux].\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to [Redux], it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```ts\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\n# NPM\r\nnpm install reselect\r\n\r\n# Yarn\r\nyarn add reselect\r\n\r\n# Bun\r\nbun add reselect\r\n\r\n# PNPM\r\npnpm add reselect\r\n```\r\n\r\n---\r\n\r\n## Basic Usage\r\n\r\nReselect exports a [`createSelector`] API, which generates memoized selector functions. [`createSelector`] accepts one or more [input selectors], which extract values from arguments, and a [result function] function that receives the extracted values and should return a derived value. If the generated [output selector] is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/reselect-example-g3k9gf?file=/src/index.js):\r\n\r\n```ts\r\nimport { createSelector } from 'reselect'\r\n\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\nconst state: RootState = {\r\n  todos: [\r\n    { id: 0, completed: false },\r\n    { id: 1, completed: true }\r\n  ],\r\n  alerts: [\r\n    { id: 0, read: false },\r\n    { id: 1, read: true }\r\n  ]\r\n}\r\n\r\nconst selectCompletedTodos = (state: RootState) => {\r\n  console.log('selector ran')\r\n  return state.todos.filter(todo => todo.completed === true)\r\n}\r\n\r\nselectCompletedTodos(state) // selector ran\r\nselectCompletedTodos(state) // selector ran\r\nselectCompletedTodos(state) // selector ran\r\n\r\nconst memoizedSelectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => {\r\n    console.log('memoized selector ran')\r\n    return todos.filter(todo => todo.completed === true)\r\n  }\r\n)\r\n\r\nmemoizedSelectCompletedTodos(state) // memoized selector ran\r\nmemoizedSelectCompletedTodos(state)\r\nmemoizedSelectCompletedTodos(state)\r\n\r\nconsole.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false\r\n\r\nconsole.log(\r\n  memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)\r\n) //=> true\r\n```\r\n\r\nAs you can see from the example above, `memoizedSelectCompletedTodos` does not run the second or third time, but we still get the same return value as last time.\r\n\r\nIn addition to skipping unnecessary recalculations, `memoizedSelectCompletedTodos` returns the existing result reference if there is no recalculation. This is important for libraries like [React-Redux] or [React] that often rely on reference equality checks to optimize UI updates.\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n  - [Redux Toolkit](#redux-toolkit)\r\n  - [Standalone](#standalone)\r\n- [Basic Usage](#basic-usage)\r\n- [Terminology](#terminology)\r\n- [How Does Reselect Work?](#how-does-reselect-work)\r\n  - [Cascading Memoization](#cascading-memoization)\r\n  - [Why Reselect Is Often Used With Redux](#why-reselect-is-often-used-with-redux)\r\n- [API](#api)\r\n  - [**`createSelector`**][`createSelector`]\r\n  - [**`createSelectorCreator`**][`createSelectorCreator`]\r\n  - [**`createStructuredSelector`**][`createStructuredSelector`]\r\n  - [**`defaultMemoize`**][`defaultMemoize`]\r\n  - [**`weakMapMemoize`**][`weakMapMemoize`]\r\n  - [**`unstable_autotrackMemoize`**][`unstable_autotrackMemoize`]\r\n- [Debugging Tools](#debuggingtools)\r\n  - [Development-Only Stability Checks](#development-only-stability-checks)\r\n  - [Output Selector Fields](#output-selector-fields)\r\n- [What's New in 5.0.0?](#v5summary)\r\n- [Optimizing Reselect](#optimizing-reselect)\r\n- [FAQ](#faq)\r\n  - [Why isn’t my selector recomputing when the input state changes?](#why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#can-i-use-reselect-without-redux)\r\n  - [How do I create a selector that takes an argument?](#how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [Can the memoization behavior be customized?](#can-the-memoization-behavior-be-customized)\r\n  - [How do I test a selector?](#how-do-i-test-a-selector)\r\n  - [Can I share a selector across multiple component instances?](#can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript Typings?](#are-there-typescript-typings)\r\n  - [I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`](#i-am-seeing-a-typescript-error-type-instantiation-is-excessively-deep-and-possibly-infinite)\r\n  - [How can I make a curried selector?](#how-can-i-make-a-curried-selector)\r\n  - [How can I make pre-typed version of `createSelector` for my root state?](#how-can-i-make-pre-typed-version-of-createselector-for-my-root-state)\r\n  - [What if I want to use `createSelector` without memoization?](#what-if-i-want-to-use-createselector-without-memoization)\r\n- [External References](#external-references)\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n- [Prior Art and Inspiration](#prior-art-and-inspiration)\r\n\r\n---\r\n\r\n## Terminology\r\n\r\n- <a name=\"selector-function\"></a>[**Selector Function**](#selector-function): A function that accepts one or more JavaScript values as arguments, and derives a result. When used with [Redux], the first argument is typically the entire Redux store state.\r\n- <a name=\"input-selectors\"></a>[**input selectors**](#input-selectors): Basic selector functions used as building blocks for creating a memoized selector. They are passed as the first argument(s) to [`createSelector`], and are called with all selector arguments. They are responsible for extracting and providing necessary values to the [result function].\r\n- <a name=\"output-selector\"></a>[**Output Selector**](#output-selector): The actual memoized selectors created by [`createSelector`].\r\n- <a name=\"result-function\"></a>[**Result Function**](#result-function): The function that comes after the [input selectors]. It takes the [input selectors]' return values as arguments and returns a result.\r\n- <a name=\"dependencies\"></a>[**`Dependencies`**](#dependencies): Same as [input selectors]. They are what the [output selector] \"depends\" on.\r\n\r\nThe below example serves as a visual aid:\r\n\r\n```ts\r\nconst outputSelector = createSelector(\r\n  [inputSelector1, inputSelector2, inputSelector3], // synonymous with `dependencies`.\r\n  resultFunc // Result function\r\n)\r\n```\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## How Does Reselect Work?\r\n\r\nReselect, at its core, is a library for creating memoized selectors in JavaScript applications. Its primary role is to efficiently compute derived data based on provided inputs. A key aspect of Reselect's internal mechanism is how it orchestrates the flow of arguments from the final selector to its constituent [input selectors].\r\n\r\n```ts\r\nconst finalSelector = (...args) => {\r\n  const extractedValues = inputSelectors.map(inputSelector =>\r\n    inputSelector(...args)\r\n  )\r\n  return resultFunc(...extractedValues)\r\n}\r\n```\r\n\r\nIn this pattern, the `finalSelector` is composed of several [input selectors], **all receiving the same arguments as the final selector**. Each input selector processes its part of the data, and the results are then combined and further processed by the [result function]. Understanding this argument flow is crucial for appreciating how Reselect optimizes data computation and minimizes unnecessary recalculations.\r\n\r\n<a id=\"cascadingmemoization\"></a>\r\n\r\n### Cascading Memoization\r\n\r\nReselect uses a two-stage \"cascading\" approach to memoizing functions:\r\n\r\n<details><summary><b>Detailed Explanation: Cascading Memoization</b></summary>\r\n\r\nThe way Reselect works can be broken down into multiple parts:\r\n\r\n1. **Initial Run**: On the first call, Reselect runs all the [input selectors], gathers their results, and passes them to the [result function].\r\n\r\n2. **Subsequent Runs**: For subsequent calls, Reselect performs two levels of checks:\r\n\r\n   - **First Level**: It compares the current arguments with the previous ones (done by `argsMemoize`).\r\n\r\n     - If they're the same, it returns the cached result without running the [input selectors] or the [result function].\r\n\r\n     - If they differ, it proceeds (\"cascades\") to the second level.\r\n\r\n   - **Second Level**: It runs the [input selectors] and compares their current results with the previous ones (done by `memoize`).\r\n     > [!NOTE]\r\n     > If any one of the [input selectors] return a different result, all [input selectors] will recalculate.\r\n     - If the results are the same, it returns the cached result without running the [result function].\r\n     - If the results differ, it runs the [result function].\r\n\r\nThis behavior is what we call **_Cascading Double-Layer Memoization_**.\r\n\r\n#### Reselect Vs Standard Memoization\r\n\r\n##### Standard Memoization\r\n\r\n![normal-memoization-function](docs/assets//normal-memoization-function.png)\r\n\r\n_Standard memoization only compares arguments. If they're the same, it returns the cached result._\r\n\r\n##### Memoization with Reselect\r\n\r\n![reselect-memoization](docs/assets//reselect-memoization.png)\r\n\r\n_Reselect adds a second layer of checks with the [input selectors]. This is crucial in [Redux] applications where state references change frequently._\r\n\r\nA normal [memoization] function will compare the arguments, and if they are the same as last time, it will skip running the function and return the cached result. However, Reselect enhances this by introducing a second tier of checks via its [input selectors]. It's possible that the arguments passed to these [input selectors] may change, yet their results remain the same. When this occurs, Reselect avoids re-executing the [result function], and returns the cached result.\r\n\r\nThis feature becomes crucial in [Redux] applications, where the `state` changes its reference anytime an `action` is dispatched.\r\n\r\n> [!NOTE]\r\n> The [input selectors] take the same arguments as the [output selector].\r\n\r\n</details>\r\n\r\n### Why Reselect Is Often Used With [Redux]\r\n\r\nWhile Reselect can be used independently from Redux, it is a standard tool used in most Redux applications to help optimize calculations and UI updates:\r\n\r\n<details><summary><b>Detailed Explanation: Reselect and Redux Optimization</b></summary>\r\n\r\nImagine you have a selector like this:\r\n\r\n```ts\r\nconst selectCompletedTodos = (state: RootState) =>\r\n  state.todos.filter(todo => todo.completed === true)\r\n```\r\n\r\nSo you decide to memoize it:\r\n\r\n```ts\r\nconst selectCompletedTodos = someMemoizeFunction((state: RootState) =>\r\n  state.todos.filter(todo => todo.completed === true)\r\n)\r\n```\r\n\r\nThen you update `state.alerts`:\r\n\r\n```ts\r\nstore.dispatch(toggleRead(0))\r\n```\r\n\r\nNow when you call `selectCompletedTodos`, it re-runs, because we have effectively broken memoization.\r\n\r\n```ts\r\nselectCompletedTodos(store.getState())\r\n// Will not run, and the cached result will be returned.\r\nselectCompletedTodos(store.getState())\r\nstore.dispatch(toggleRead(0))\r\n// It recalculates.\r\nselectCompletedTodos(store.getState())\r\n```\r\n\r\nBut why? `selectCompletedTodos` only needs to access `state.todos`, and has nothing to do with `state.alerts`, so why have we broken memoization? Well that's because in [Redux] anytime you make a change to the root `state`, it gets shallowly updated, which means its reference changes, therefore a normal memoization function will always fail the comparison check on the arguments.\r\n\r\nBut with Reselect, we can do something like this:\r\n\r\n```ts\r\nconst selectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.filter(todo => todo.completed === true)\r\n)\r\n```\r\n\r\nAnd now we have achieved memoization:\r\n\r\n```ts\r\nselectCompletedTodos(store.getState())\r\n// Will not run, and the cached result will be returned.\r\nselectCompletedTodos(store.getState())\r\nstore.dispatch(toggleRead(0))\r\n// The `input selectors` will run, but the `result function` is\r\n// skipped and the cached result will be returned.\r\nselectCompletedTodos(store.getState())\r\n```\r\n\r\nEven when the overall `state` changes, Reselect ensures efficient memoization through its unique approach. The [result function] doesn't re-run if the relevant part of the `state` (in this case `state.todos`), remains unchanged. This is due to Reselect's [**_Cascading Double-Layer Memoization_**][**_Cascading Memoization_**]. The first layer checks the entire `state`, and the second layer checks the results of the [input selectors]. If the first layer fails (due to a change in the overall `state`) but the second layer succeeds (because `state.todos` is unchanged), Reselect skips recalculating the [result function]. This dual-check mechanism makes Reselect particularly effective in [Redux] applications, ensuring computations are only done when truly necessary.\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## API\r\n\r\n<a id=\"createselector\"></a>\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, createSelectorOptions?)\r\n\r\n<b>Description</b>\r\n\r\nAccepts one or more \"[input selectors]\" (either as separate arguments or a single array),\r\na single \"[result function]\", and an optional options object, and\r\ngenerates a memoized selector function.\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                     | Description                                                                       |\r\n| :----------------------- | :-------------------------------------------------------------------------------- |\r\n| `inputSelectors`         | An array of [input selectors], can also be passed as separate arguments.          |\r\n| `resultFunc`             | A function that takes the results of the [input selectors] as separate arguments. |\r\n| `createSelectorOptions?` | An optional options object that allows for further customization per selector.    |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized [output selector].\r\n\r\n<details><summary><b>Type parameters</b></summary>\r\n\r\n| Name                          | Description                                                                                                                                                                                            |\r\n| :---------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `InputSelectors`              | The type of the [input selectors] array.                                                                                                                                                               |\r\n| `Result`                      | The return type of the [result function] as well as the [output selector].                                                                                                                             |\r\n| `OverrideMemoizeFunction`     | The type of the optional `memoize` function that could be passed into the options object to override the original `memoize` function that was initially passed into [`createSelectorCreator`].         |\r\n| `OverrideArgsMemoizeFunction` | The type of the optional `argsMemoize` function that could be passed into the options object to override the original `argsMemoize` function that was initially passed into [`createSelectorCreator`]. |\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"createselectorcreator\" ></a>\r\n\r\n### createSelectorCreator(memoize | options, ...memoizeOptions)\r\n\r\n<b>Description</b>\r\n\r\nAccepts either a `memoize` function and `...memoizeOptions` rest parameter, or since 5.0.0 an `options` object containing a `memoize` function and creates a custom selector creator function.\r\n\r\n<b>Parameters (since 5.0.0)</b>\r\n\r\n| Name                           | Description                                                                                                                                                                                                                                                                                                         |\r\n| :----------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\r\n| `options`                      | An options object containing the `memoize` function responsible for memoizing the `resultFunc` inside [`createSelector`] (e.g., `defaultMemoize` or `weakMapMemoize`). It also provides additional options for customizing memoization. While the `memoize` property is mandatory, the rest are optional.           |\r\n| `options.argsMemoize?`         | The optional memoize function that is used to memoize the arguments passed into the [output selector] generated by [`createSelector`] (e.g., `defaultMemoize` or `weakMapMemoize`). <br /> **`Default`** `defaultMemoize`                                                                                           |\r\n| `options.argsMemoizeOptions?`  | Optional configuration options for the `argsMemoize` function. These options are passed to the `argsMemoize` function as the second argument. <br /> since 5.0.0                                                                                                                                                    |\r\n| `options.devModeChecks?` | Overrides the settings for the global development mode checks for the selector. <br /> since 5.0.0 |\r\n| `options.memoize`              | The memoize function that is used to memoize the `resultFunc` inside [`createSelector`] (e.g., `defaultMemoize` or `weakMapMemoize`). since 5.0.0                                                                                                                                                                   |\r\n| `options.memoizeOptions?`      | Optional configuration options for the `memoize` function. These options are passed to the `memoize` function as the second argument. <br /> since 5.0.0                                                                                                                                                            |\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                        | Description                                                                                                                                        |\r\n| :-------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `memoize`                   | The `memoize` function responsible for memoizing the `resultFunc` inside [`createSelector`] (e.g., `defaultMemoize` or `weakMapMemoize`).          |\r\n| `...memoizeOptionsFromArgs` | Optional configuration options for the memoization function. These options are then passed to the memoize function as the second argument onwards. |\r\n\r\n<b>Returns</b>\r\n\r\nA customized [`createSelector`] function.\r\n\r\n<details><summary><b>Type parameters</b></summary>\r\n\r\n| Name                  | Description                                                                                                                                                                                                                                                    |\r\n| :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `MemoizeFunction`     | The type of the memoize function that is used to memoize the `resultFunc` inside [`createSelector`] (e.g., `defaultMemoize` or `weakMapMemoize`).                                                                                                              |\r\n| `ArgsMemoizeFunction` | The type of the optional memoize function that is used to memoize the arguments passed into the [output selector] generated by [`createSelector`] (e.g., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n##### Using `options` (since 5.0.0)\r\n\r\n```ts\r\nconst customCreateSelector = createSelectorCreator({\r\n  memoize: customMemoize, // Function to be used to memoize `resultFunc`\r\n  memoizeOptions: [memoizeOption1, memoizeOption2], // Options passed to `customMemoize` as the second argument onwards\r\n  argsMemoize: customArgsMemoize, // Function to be used to memoize the selector's arguments\r\n  argsMemoizeOptions: [argsMemoizeOption1, argsMemoizeOption2] // Options passed to `customArgsMemoize` as the second argument onwards\r\n})\r\n\r\nconst customSelector = customCreateSelector(\r\n  [inputSelector1, inputSelector2],\r\n  resultFunc // `resultFunc` will be passed as the first argument to `customMemoize`\r\n)\r\n\r\ncustomSelector(\r\n  ...selectorArgs // Will be memoized by `customArgsMemoize`\r\n)\r\n```\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n##### Using `memoize` and `...memoizeOptions`\r\n\r\n`createSelectorCreator` can be used to make a customized version of [`createSelector`].\r\n\r\nThe `memoize` argument is a memoization function to replace `weakMapMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```ts\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // Function to be used to memoize `resultFunc`\r\n  option1, // `option1` will be passed as second argument to `customMemoize`\r\n  option2, // `option2` will be passed as third argument to `customMemoize`\r\n  option3 // `option3` will be passed as fourth argument to `customMemoize`\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  [inputSelector1, inputSelector2],\r\n  resultFunc // `resultFunc` will be passed as first argument to `customMemoize`\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```ts\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\n##### Additional Examples\r\n\r\n###### Customize `equalityCheck` for `defaultMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  [state => state.values.filter(val => val < 5)],\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n###### Use memoize function from Lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\n\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\n\r\nconst selector = customSelectorCreator(\r\n  [state => state.a, state => state.b],\r\n  (a, b) => a + b\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"createstructuredselector\"></a>\r\n\r\n### createStructuredSelector({ inputSelectorsObject }, selectorCreator = createSelector)\r\n\r\n<b>Description</b>\r\n\r\nA convenience function that simplifies returning an object made up of selector results.\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                   | Description                                                            |\r\n| :--------------------- | :--------------------------------------------------------------------- |\r\n| `inputSelectorsObject` | A key value pair consisting of input selectors.                        |\r\n| `selectorCreator?`     | A custom selector creator function. It defaults to [`createSelector`]. |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized structured selector.\r\n\r\n<details><summary><b>Type parameters</b></summary>\r\n\r\n| Name                   | Description                                                                                                                                                   |\r\n| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ |\r\n| `InputSelectorsObject` | The shape of the [input selectors] object.                                                                                                                    |\r\n| `MemoizeFunction`      | The type of the memoize function that is used to create the structured selector. It defaults to `weakMapMemoize`.                                             |\r\n| `ArgsMemoizeFunction`  | The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `weakMapMemoize`. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n##### Modern Use Case\r\n\r\n```ts\r\nimport { createSelector, createStructuredSelector } from 'reselect'\r\n\r\ninterface RootState {\r\n  todos: {\r\n    id: number\r\n    completed: boolean\r\n    title: string\r\n    description: string\r\n  }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\n// This:\r\nconst structuredSelector = createStructuredSelector(\r\n  {\r\n    todos: (state: RootState) => state.todos,\r\n    alerts: (state: RootState) => state.alerts,\r\n    todoById: (state: RootState, id: number) => state.todos[id]\r\n  },\r\n  createSelector\r\n)\r\n\r\n// Is essentially the same as this:\r\nconst selector = createSelector(\r\n  [\r\n    (state: RootState) => state.todos,\r\n    (state: RootState) => state.alerts,\r\n    (state: RootState, id: number) => state.todos[id]\r\n  ],\r\n  (todos, alerts, todoById) => {\r\n    return {\r\n      todos,\r\n      alerts,\r\n      todoById\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIn your component:\r\n\r\n```tsx\r\ninterface Props {\r\n  id: number\r\n}\r\n\r\nconst MyComponent: FC<Props> = ({ id }) => {\r\n  const { todos, alerts, todoById } = useSelector(state =>\r\n    structuredSelector(state, id)\r\n  )\r\n\r\n  return (\r\n    <div>\r\n      Next to do is:\r\n      <h2>{todoById.title}</h2>\r\n      <p>Description: {todoById.description}</p>\r\n      <ul>\r\n        <h3>All other to dos:</h3>\r\n        {todos.map(todo => (\r\n          <li key={todo.id}>{todo.title}</li>\r\n        ))}\r\n      </ul>\r\n    </div>\r\n  )\r\n}\r\n```\r\n\r\n##### Simple Use Case\r\n\r\n```ts\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n### Memoization Functions\r\n\r\nReselect comes with a selection of memoization functions, each uniquely designed to address different scenarios and performance requirements. By effectively leveraging these functions, you can significantly enhance the efficiency and responsiveness of your applications.\r\n\r\n<a id=\"defaultmemoize\"></a>\r\n\r\n#### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)\r\n\r\n<b>Description</b>\r\n\r\nThe standard memoize function used by [`createSelector`].\r\n\r\nIt has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (since 4.1.0).\r\n\r\nIt determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using [reference equality][Reference Equality Check]:\r\n\r\n```ts\r\nconst defaultEqualityCheck = (previousValue: any, currentValue: any) => {\r\n  return previousValue === currentValue\r\n}\r\n```\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                     | Description                                                 |\r\n| :----------------------- | :---------------------------------------------------------- |\r\n| `func`                   | The function to be memoized.                                |\r\n| `equalityCheckOrOptions` | Either an `equality check` function or an `options` object. |\r\n\r\nSince 4.1.0, `defaultMemoize` also accepts an options object as its first argument instead of an `equalityCheck` function. The `options` object may contain:\r\n\r\n```ts\r\ntype EqualityFn = (a: any, b: any) => boolean\r\n\r\ninterface DefaultMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\n| Name                  | Description                                                                                                                                                                                                                                                                                                                                                                         |\r\n| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `equalityCheck`       | Used to compare the individual arguments of the provided calculation function. <br /> **`Default`** = `defaultEqualityCheck`                                                                                                                                                                                                                                                        |\r\n| `resultEqualityCheck` | If provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This addresses the common <code>todos.map(todo => todo.id)</code> use case, where an update to another field in the original data causes a recalculation due to changed references, but the output is still effectively the same. |\r\n| `maxSize`             | The cache size for the selector. If greater than 1, the selector will use an LRU cache internally. <br /> **`Default`** = 1                                                                                                                                                                                                                                                         |\r\n\r\n> [!WARNING]\r\n> If `resultEqualityCheck` is used inside `argsMemoizeOptions` it has no effect.\r\n\r\n<b>Returns</b>\r\n\r\nA memoized function with a `.clearCache()` method attached.\r\n\r\n<details><summary><b>Type parameters</b></summary>\r\n\r\n| Name   | Description                                |\r\n| :----- | :----------------------------------------- |\r\n| `Func` | The type of the function that is memoized. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n###### Using `defaultMemoize` with [`createSelector`]\r\n\r\n```ts\r\nimport { shallowEqual } from 'react-redux'\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectTodoIds = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id),\r\n  {\r\n    memoizeOptions: {\r\n      equalityCheck: shallowEqual,\r\n      resultEqualityCheck: shallowEqual,\r\n      maxSize: 10\r\n    },\r\n    argsMemoizeOptions: {\r\n      equalityCheck: shallowEqual,\r\n      resultEqualityCheck: shallowEqual,\r\n      maxSize: 10\r\n    }\r\n  }\r\n)\r\n```\r\n\r\n###### Using `defaultMemoize` with [`createSelectorCreator`]\r\n\r\n```ts\r\nimport { shallowEqual } from 'react-redux'\r\nimport { createSelectorCreator, defaultMemoize } from 'reselect'\r\n\r\nconst createSelectorShallowEqual = createSelectorCreator({\r\n  memoize: defaultMemoize,\r\n  memoizeOptions: {\r\n    equalityCheck: shallowEqual,\r\n    resultEqualityCheck: shallowEqual,\r\n    maxSize: 10\r\n  },\r\n  argsMemoize: defaultMemoize,\r\n  argsMemoizeOptions: {\r\n    equalityCheck: shallowEqual,\r\n    resultEqualityCheck: shallowEqual,\r\n    maxSize: 10\r\n  }\r\n})\r\n\r\nconst selectTodoIds = createSelectorShallowEqual(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id)\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"weakmapmemoize\"></a>\r\n\r\n#### weakMapMemoize(func) - (since 5.0.0)\r\n\r\n<b>Description</b>\r\n\r\n[`defaultMemoize`] has to be explicitly configured to have a cache size larger than 1, and uses an LRU cache internally.\r\n\r\n`weakMapMemoize` creates a tree of [`WeakMap`]-based cache nodes based on the identity of the arguments it's been called with (in this case, the extracted values from your input selectors). **This allows `weakMapMemoize` to have an effectively infinite cache size**. Cache results will be kept in memory as long as references to the arguments still exist, and then cleared out as the arguments are garbage-collected.\r\n\r\n<details><summary><b>Design Tradeoffs</b></summary>\r\n\r\n- Pros:\r\n\r\n  - It has an effectively infinite cache size, but you have no control over\r\n    how long values are kept in cache as it's based on garbage collection and [`WeakMap`]s.\r\n\r\n- Cons:\r\n  - There's currently no way to alter the argument comparisons. They're based on [strict reference equality][Reference Equality Check].\r\n\r\n</details>\r\n\r\n<details><summary><b>Use Cases</b></summary>\r\n\r\n- This memoizer is likely best used for cases where you need to call the\r\n  same selector instance with many different arguments, such as a single\r\n  selector instance that is used in a list item component and called with\r\n  item IDs like:\r\n\r\n```ts\r\nuseSelector(state => selectSomeData(state, id))\r\n```\r\n\r\nPrior to `weakMapMemoize`, you had this problem:\r\n\r\n```ts\r\ninterface RootState {\r\n  items: { id: number; category: string; name: string }[]\r\n}\r\n\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics') // Selector runs again!\r\n```\r\n\r\nBefore you could solve this in a number of different ways:\r\n\r\n1. Set the `maxSize` with [`defaultMemoize`]:\r\n\r\n```ts\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category),\r\n  {\r\n    memoizeOptions: {\r\n      maxSize: 10\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nBut this required having to know the cache size ahead of time.\r\n\r\n2. Create unique selector instances using [`useMemo`].\r\n\r\n```tsx\r\nconst makeSelectItemsByCategory = (category: string) =>\r\n  createSelector([(state: RootState) => state.items], items =>\r\n    items.filter(item => item.category === category)\r\n  )\r\n\r\ninterface Props {\r\n  category: string\r\n}\r\n\r\nconst MyComponent: FC<Props> = ({ category }) => {\r\n  const selectItemsByCategory = useMemo(\r\n    () => makeSelectItemsByCategory(category),\r\n    [category]\r\n  )\r\n\r\n  const itemsByCategory = useSelector(selectItemsByCategory)\r\n\r\n  return (\r\n    <div>\r\n      {itemsByCategory.map(item => (\r\n        <div key={item.id}>{item.name}</div>\r\n      ))}\r\n    </div>\r\n  )\r\n}\r\n```\r\n\r\n3. Using [`useCallback`].\r\n\r\n```tsx\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n\r\nconst MyComponent: FC<Props> = ({ category }) => {\r\n  const selectItemsByCategoryMemoized = useCallback(selectItemsByCategory, [])\r\n\r\n  const itemsByCategory = useSelector(state =>\r\n    selectItemsByCategoryMemoized(state, category)\r\n  )\r\n\r\n  return (\r\n    <div>\r\n      {itemsByCategory.map(item => (\r\n        <div key={item.id}>{item.name}</div>\r\n      ))}\r\n    </div>\r\n  )\r\n}\r\n```\r\n\r\n4. Use [`re-reselect`]:\r\n\r\n```ts\r\nimport { createCachedSelector } from 're-reselect'\r\n\r\nconst selectItemsByCategory = createCachedSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)((state: RootState, category: string) => category)\r\n```\r\n\r\nStarting in 5.0.0, you can eliminate this problem using `weakMapMemoize`.\r\n\r\n```ts\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category),\r\n  {\r\n    memoize: weakMapMemoize,\r\n    argsMemoize: weakMapMemoize\r\n  }\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics') // Cached\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics') // Still cached!\r\n```\r\n\r\nThis solves the problem of having to know and set the cache size prior to creating a memoized selector. Because `weakMapMemoize` essentially provides a dynamic cache size out of the box.\r\n\r\n</details>\r\n\r\n<b>Parameters</b>\r\n\r\n| Name   | Description                  |\r\n| :----- | :--------------------------- |\r\n| `func` | The function to be memoized. |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized function with a `.clearCache()` method attached.\r\n\r\n<details><summary><b>Type parameters</b></summary>\r\n\r\n| Name   | Description                                |\r\n| :----- | :----------------------------------------- |\r\n| `Func` | The type of the function that is memoized. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n###### Using `weakMapMemoize` with [`createSelector`]\r\n\r\n```ts\r\nimport { createSelector, weakMapMemoize } from 'reselect'\r\n\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category),\r\n  {\r\n    memoize: weakMapMemoize,\r\n    argsMemoize: weakMapMemoize\r\n  }\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\n```\r\n\r\n###### Using `weakMapMemoize` with [`createSelectorCreator`]\r\n\r\n```ts\r\nimport { createSelectorCreator, weakMapMemoize } from 'reselect'\r\n\r\nconst createSelectorWeakMap = createSelectorCreator({\r\n  memoize: weakMapMemoize,\r\n  argsMemoize: weakMapMemoize\r\n})\r\n\r\nconst selectItemsByCategory = createSelectorWeakMap(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"unstable_autotrackMemoize\"></a>\r\n\r\n#### unstable_autotrackMemoize(func) - (since 5.0.0)\r\n\r\n<b>Description</b>\r\n\r\nUses an \"auto-tracking\" approach inspired by the work of the Ember Glimmer team. It uses a Proxy to wrap arguments and track accesses to nested fields in your selector on first read. Later, when the selector is called with new arguments, it identifies which accessed fields have changed and only recalculates the result if one or more of those accessed fields have changed. This allows it to be more precise than the shallow equality checks in `defaultMemoize`.\r\n\r\n> [!WARNING]\r\n> This API is still experimental and undergoing testing.\r\n\r\n<details><summary><b>Design Tradeoffs</b></summary>\r\n\r\n- Pros:\r\n\r\n  - It is likely to avoid excess calculations and recalculate fewer times than `defaultMemoize` will, which may also result in fewer component re-renders.\r\n\r\n- Cons:\r\n\r\n  - It only has a cache size of 1.\r\n  - It is slower than `defaultMemoize`, because it has to do more work. (How much slower is dependent on the number of accessed fields in a selector, number of calls, frequency of input changes, etc)\r\n  - It can have some unexpected behavior. Because it tracks nested field accesses, cases where you don't access a field will not recalculate properly. For example, a badly-written selector like:\r\n\r\n  ```ts\r\n  createSelector([state => state.todos], todos => todos)\r\n  ```\r\n\r\n  that just immediately returns the extracted value will never update, because it doesn't see any field accesses to check.\r\n\r\n</details>\r\n\r\n<details><summary><b>Use Cases</b></summary>\r\n\r\n- It is likely best used for cases where you need to access specific nested fields in data, and avoid recalculating if other fields in the same data objects are immutably updated.\r\n\r\n</details>\r\n\r\n<b>Parameters</b>\r\n\r\n| Name   | Description                  |\r\n| :----- | :--------------------------- |\r\n| `func` | The function to be memoized. |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized function with a `.clearCache()` method attached.\r\n\r\n<details><summary><b>Type parameters</b></summary>\r\n\r\n| Name   | Description                                |\r\n| :----- | :----------------------------------------- |\r\n| `Func` | The type of the function that is memoized. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n###### Using `unstable_autotrackMemoize` with [`createSelector`]\r\n\r\n```ts\r\nimport { unstable_autotrackMemoize, createSelector } from 'reselect'\r\n\r\nconst selectTodoIds = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id),\r\n  { memoize: unstable_autotrackMemoize }\r\n)\r\n```\r\n\r\n###### Using `unstable_autotrackMemoize` with [`createSelectorCreator`]\r\n\r\n```ts\r\nimport { unstable_autotrackMemoize, createSelectorCreator } from 'reselect'\r\n\r\nconst createSelectorAutotrack = createSelectorCreator({\r\n  memoize: unstable_autotrackMemoize\r\n})\r\n\r\nconst selectTodoIds = createSelectorAutotrack(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id)\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"debuggingtools\"></a>\r\n\r\n## Debugging Tools\r\n\r\n<a id=\"developmentonlychecks\"></a>\r\n\r\n### Development-Only Checks\r\n\r\nReselect includes extra checks in development mode to help catch and warn about mistakes in selector behavior.\r\n\r\n<a id=\"inputstabilitycheck\"></a>\r\n\r\n#### `inputStabilityCheck`\r\n\r\nDue to how [**_Cascading Memoization_**] works in Reselect, it is crucial that your [input selectors] do not return a new reference on each run. If an [input selector][input selectors] always returns a new reference, like\r\n\r\n```ts\r\nstate => ({ a: state.a, b: state.b })\r\n```\r\n\r\nor\r\n\r\n```ts\r\nstate => state.todos.map(todo => todo.id)\r\n```\r\n\r\nthat will cause the selector to never memoize properly.\r\nSince this is a common mistake, we've added a development mode check to catch this. By default, [`createSelector`] will now run the [input selectors] twice during the first call to the selector. If the result appears to be different for the same call, it will log a warning with the arguments and the two different sets of extracted input values.\r\n\r\n```ts\r\ntype DevModeCheckFrequency = 'always' | 'once' | 'never'\r\n```\r\n\r\n| Possible Values | Description                                     |\r\n| :-------------- | :---------------------------------------------- |\r\n| `once`          | Run only the first time the selector is called. |\r\n| `always`        | Run every time the selector is called.          |\r\n| `never`         | Never run the input stability check.            |\r\n\r\n> [!IMPORTANT]\r\n> The input stability check is automatically disabled in production environments.\r\n\r\nYou can configure this behavior in two ways:\r\n\r\n<a id=\"setglobaldevmodechecks\"></a>\r\n\r\n##### 1. Globally through `setGlobalDevModeChecks`:\r\n\r\nA `setGlobalDevModeChecks` function is exported from Reselect, which should be called with the desired setting.\r\n\r\n```ts\r\nimport { setGlobalDevModeChecks } from 'reselect'\r\n\r\n// Run only the first time the selector is called. (default)\r\nsetGlobalDevModeChecks({ inputStabilityCheck: 'once' })\r\n\r\n// Run every time the selector is called.\r\nsetGlobalDevModeChecks({ inputStabilityCheck: 'always' })\r\n\r\n// Never run the input stability check.\r\nsetGlobalDevModeChecks({ inputStabilityCheck: 'never' })\r\n```\r\n\r\n##### 2. Per selector by passing an `inputStabilityCheck` option directly to [`createSelector`]:\r\n\r\n```ts\r\n// Create a selector that double-checks the results of input selectors every time it runs.\r\nconst selectCompletedTodosLength = createSelector(\r\n  [\r\n    // ❌ Incorrect Use Case: This input selector will not be memoized properly since it always returns a new reference.\r\n    (state: RootState) =>\r\n      state.todos.filter(({ completed }) => completed === true)\r\n  ],\r\n  completedTodos => completedTodos.length,\r\n  // Will override the global setting.\r\n  { devModeChecks: { inputStabilityCheck: 'always' } }\r\n)\r\n```\r\n\r\n> [!WARNING]\r\n> This will override the global input stability check set by calling `setGlobalDevModeChecks`.\r\n\r\n<a id=\"identityfunctioncheck\"></a>\r\n\r\n#### `identityFunctionCheck`\r\n\r\nWhen working with Reselect, it's crucial to adhere to a fundamental philosophy regarding the separation of concerns between extraction and transformation logic.\r\n\r\n- **Extraction Logic**: This refers to operations like `state => state.todos`, which should be placed in [input selectors]. Extraction logic is responsible for retrieving or 'selecting' data from a broader state or dataset.\r\n\r\n- **Transformation Logic**: In contrast, transformation logic, such as `todos => todos.map(({ id }) => id)`, belongs in the [result function]. This is where you manipulate, format, or transform the data extracted by the input selectors.\r\n\r\nMost importantly, effective memoization in Reselect hinges on following these guidelines. Memoization, only functions correctly when extraction and transformation logic are properly segregated. By keeping extraction logic in input selectors and transformation logic in the result function, Reselect can efficiently determine when to reuse cached results and when to recompute them. This not only enhances performance but also ensures the consistency and predictability of your selectors.\r\n\r\nFor memoization to work as intended, it's imperative to follow both guidelines. If either is disregarded, memoization will not function properly. Consider the following example for clarity:\r\n\r\n```ts\r\n// ❌ Incorrect Use Case: This will not memoize correctly, and does nothing useful!\r\nconst brokenSelector = createSelector(\r\n  // ✔️ GOOD: Contains extraction logic.\r\n  [(state: RootState) => state.todos],\r\n  // ❌ BAD: Does not contain transformation logic.\r\n  todos => todos\r\n)\r\n```\r\n\r\n```ts\r\ntype DevModeCheckFrequency = 'always' | 'once' | 'never'\r\n```\r\n\r\n| Possible Values | Description                                     |\r\n| :-------------- | :---------------------------------------------- |\r\n| `once`          | Run only the first time the selector is called. |\r\n| `always`        | Run every time the selector is called.          |\r\n| `never`         | Never run the identity function check.          |\r\n\r\n> [!IMPORTANT]\r\n> The identity function check is automatically disabled in production environments.\r\n\r\nYou can configure this behavior in two ways:\r\n\r\n<a id=\"setGlobalDevModeChecks\"></a>\r\n\r\n##### 1. Globally through `setGlobalDevModeChecks`:\r\n\r\n```ts\r\nimport { setGlobalDevModeChecks } from 'reselect'\r\n\r\n// Run only the first time the selector is called. (default)\r\nsetGlobalDevModeChecks({ identityFunctionCheck: 'once' })\r\n\r\n// Run every time the selector is called.\r\nsetGlobalDevModeChecks({ identityFunctionCheck: 'always' })\r\n\r\n// Never run the identity function check.\r\nsetGlobalDevModeChecks({ identityFunctionCheck: 'never' })\r\n```\r\n\r\n##### 2. Per selector by passing an `identityFunctionCheck` option directly to [`createSelector`]:\r\n\r\n```ts\r\n// Create a selector that checks to see if the result function is an identity function.\r\nconst selectTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  // This result function does not contain any transformation logic.\r\n  todos => todos,\r\n  // Will override the global setting.\r\n  { devModeChecks: { identityFunctionCheck: 'always' } }\r\n)\r\n```\r\n\r\n<a id=\"outputselectorfields\"></a>\r\n\r\n### Output Selector Fields\r\n\r\nThe output selectors created by <code>createSelector</code> have several additional properties attached to them:\r\n\r\n| Name                            | Description                                                                                                                                                                                   |\r\n| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `resultFunc`                    | The final function passed to [`createSelector`].                                                                                                                                              |\r\n| `memoizedResultFunc`            | The memoized version of `resultFunc`.                                                                                                                                                         |\r\n| `lastResult`                    | Returns the last result calculated by `memoizedResultFunc`.                                                                                                                                   |\r\n| `dependencies`                  | The array of the input selectors used by [`createSelector`] to compose `resultFunc`.                                                                                                          |\r\n| `recomputations`                | Counts the number of times `memoizedResultFunc` has been recalculated.                                                                                                                        |\r\n| `resetRecomputations`           | Resets the count of `recomputations` count to 0.                                                                                                                                              |\r\n| `dependencyRecomputations`      | Counts the number of times the [input selectors] ([`dependencies`]) have been recalculated. This is distinct from `recomputations`, which tracks the recalculations of the [result function]. |\r\n| `resetDependencyRecomputations` | Resets the `dependencyRecomputations` count to 0.                                                                                                                                             |\r\n| `memoize`                       | Function used to memoize the `resultFunc`.                                                                                                                                                    |\r\n| `argsMemoize`                   | Function used to memoize the arguments passed into the [output selector].                                                                                                                     |\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"v5summary\"></a>\r\n\r\n## What's New in 5.0.0?\r\n\r\nVersion 5.0.0 introduces several new features and improvements:\r\n\r\n- **Customization Enhancements**:\r\n\r\n  - Added the ability to pass an options object to [`createSelectorCreator`], allowing for customized `memoize` and `argsMemoize` functions, alongside their respective options (`memoizeOptions` and `argsMemoizeOptions`).\r\n  - The [`createSelector`] function now supports direct customization of `memoize` and `argsMemoize` within its options object.\r\n\r\n- **Memoization Functions**:\r\n\r\n  - Introduced new experimental memoization functions: `weakMapMemoize` and `unstable_autotrackMemoize`.\r\n  - Incorporated `memoize` and `argsMemoize` into the [output selector fields] for debugging purposes.\r\n\r\n- **TypeScript Support and Performance**:\r\n\r\n  - Discontinued support for TypeScript versions below 4.7, aligning with modern TypeScript features.\r\n  - Significantly improved TypeScript performance for nesting [output selector]s. The nesting limit has increased from approximately 8 to around 30 [output selector]s, greatly reducing the occurrence of the infamous `Type instantiation is excessively deep and possibly infinite` error.\r\n\r\n- **Selector API Enhancements**:\r\n\r\n  - Removed the second overload of `createStructuredSelector` due to its susceptibility to runtime errors.\r\n  - Added the `TypedStructuredSelectorCreator` utility type (_currently a work-in-progress_) to facilitate the creation of a pre-typed version of `createStructuredSelector` for your root state.\r\n\r\n- **Additional Functionalities**:\r\n\r\n  - Added `dependencyRecomputations` and `resetDependencyRecomputations` to the [output selector fields]. These additions provide greater control and insight over [input selectors], complementing the new `argsMemoize` API.\r\n  - Introduced `inputStabilityCheck`, a development tool that runs the [input selectors] twice using the same arguments and triggers a warning If they return differing results for the same call.\r\n  - Introduced `identityFunctionCheck`, a development tool that checks to see if the [result function] returns its own input.\r\n\r\nThese updates aim to enhance flexibility, performance, and developer experience. For detailed usage and examples, refer to the updated documentation sections for each feature.\r\n\r\n- **Breaking Changes**:\r\n\r\n  - Removed `ParametricSelector` and `OutputParametricSelector` types. Their functionalities are now integrated into `Selector` and `OutputSelector` respectively, which inherently support additional parameters.\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"optimizingreselect\"></a>\r\n\r\n## Optimizing Reselect\r\n\r\n### Common Mistakes\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nA somewhat common mistake is to write an [input selector][input selectors] that extracts a value or does some derivation, and a [result function] that just returns its result:\r\n\r\n```ts\r\n// ❌ BROKEN: this will not memoize correctly, and does nothing useful!\r\nconst brokenSelector = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos\r\n)\r\n```\r\n\r\nAny [result function] that just returns its inputs is incorrect! The [result function] should always have the transformation logic.\r\n\r\nSimilarly:\r\n\r\n```ts\r\n// ❌ BROKEN: this will not memoize correctly!\r\nconst brokenSelector = createSelector(\r\n  [(state: RootState) => state],\r\n  state => state.todos\r\n)\r\n```\r\n\r\n</details>\r\n\r\n### Handling Empty Array Results\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nTo reduce recalculations, use a predefined empty array when `array.filter` or similar methods result in an empty array.\r\n\r\nSo you can have a pattern like this:\r\n\r\n```ts\r\ninterface RootState {\r\n  todos: {\r\n    id: number\r\n    title: string\r\n    description: string\r\n    completed: boolean\r\n  }[]\r\n}\r\n\r\nconst EMPTY_ARRAY: [] = []\r\n\r\nconst selectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => {\r\n    const completedTodos = todos.filter(todo => todo.completed === true)\r\n    return completedTodos.length === 0 ? EMPTY_ARRAY : completedTodos\r\n  }\r\n)\r\n```\r\n\r\nOr to avoid repetition, you can create a wrapper function and reuse it:\r\n\r\n```ts\r\nconst EMPTY_ARRAY: [] = []\r\n\r\nexport const fallbackToEmptyArray = <T>(array: T[]) => {\r\n  return array.length === 0 ? EMPTY_ARRAY : array\r\n}\r\n\r\nconst selectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => {\r\n    return fallbackToEmptyArray(todos.filter(todo => todo.completed === true))\r\n  }\r\n)\r\n```\r\n\r\nThis way if the [result function] returns an empty array twice in a row, your component will not re-render due to a stable empty array reference:\r\n\r\n```ts\r\nconst completedTodos = selectCompletedTodos(store.getState())\r\n\r\nstore.dispatch(addTodo())\r\n\r\nconsole.log(completedTodos === selectCompletedTodos(store.getState())) //=> true\r\n```\r\n\r\n</details>\r\n\r\n### Best Practices\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nThere are a few details that will help you skip running as many functions as possible and get the best possible performance out of Reselect:\r\n\r\n- Due to the [**_Cascading Memoization_**] in Reselect, The first layer of checks is upon the arguments that are passed to the [output selector], therefore it's best to maintain the same reference for the arguments as much as possible.\r\n- In [Redux], your state will change reference when updated. But it's best to keep the additional arguments as simple as possible, you can pass in objects or array as long as their reference does not change. Or you can pass in primitives like numbers for ids.\r\n- Keep your [input selectors] as simple as possible. It's best if they mostly consist of field accessors like `state => state.todos` or argument providers like `(state, id) => id`. You should not be doing any sort of calculation inside [input selectors], and you should definitely not be returning an object or array with a new reference each time.\r\n- The [result function] is only re-run as a last resort. So make sure to put any and all calculations inside your [result function]. That way, Reselect will only run those calculations if all other checks fail.\r\n\r\nThis:\r\n\r\n```ts\r\n// ✔️ This is optimal because we have less calculations in input selectors and more in the result function.\r\nconst selectorGood = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => someExpensiveComputation(todos)\r\n)\r\n```\r\n\r\nIs preferable to this:\r\n\r\n```ts\r\n// ❌ This is not optimal!\r\nconst selectorBad = createSelector(\r\n  [(state: RootState) => someExpensiveComputation(state.todos)],\r\n  someOtherCalculation\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## FAQ\r\n\r\n### Why isn’t my selector recomputing when the input state changes?\r\n\r\nCheck that your memoization function is compatible with your state update function (i.e. the reducer if you are using [Redux]). For example, a selector created with [`createSelector`] will not work with a state update function that mutates an existing object instead of creating a new one each time. [`createSelector`] uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using [Redux], mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\n### Why is my selector recomputing when the input state stays the same?\r\n\r\nTo address unexpected recomputations in your selector, first ensure that `inputStabilityCheck` is set to either `'always'` or `'once'`. This setting aids in debugging by monitoring the stability of your inputs. Additionally, utilize [output selector fields] such as `recomputations`, `resetRecomputations`, `dependencyRecomputations`, and `resetDependencyRecomputations`. These tools help identify the source of the issue.\r\n\r\nKeep an eye on the `dependencyRecomputations` count. If it increases while `recomputations` remains the same, it suggests that your arguments are changing references but your [input selectors] are stable which is typically the desired behavior.\r\n\r\n<details><summary><b>Detailed Explanation: Selector Recomputations</b></summary>\r\n\r\nTo delve deeper, you can determine which arguments are changing references too frequently by using the `argsMemoizeOptions` and `equalityCheck`. Consider the following example:\r\n\r\n```ts\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean; type: string }[]\r\n}\r\n\r\nconst selectAlertsByType = createSelector(\r\n  [\r\n    (state: RootState) => state.alerts,\r\n    (state: RootState, type: string) => type\r\n  ],\r\n  (alerts, type) => alerts.filter(todo => todo.type === type),\r\n  {\r\n    argsMemoizeOptions: {\r\n      // This will check the arguments passed to the output selector.\r\n      equalityCheck: (a, b) => {\r\n        if (a !== b) {\r\n          console.log('Changed argument:', a, 'to', b)\r\n        }\r\n        return a === b\r\n      }\r\n    }\r\n  }\r\n)\r\n```\r\n\r\n</details>\r\n\r\n### Can I use Reselect without [Redux]?\r\n\r\nYes. Reselect has no dependencies on any other package, so although it was designed to be used with [Redux] it can be used independently. It can be used with any plain JS data, such as typical [React] state values, as long as that data is being updated immutably.\r\n\r\n### How do I create a selector that takes an argument?\r\n\r\nEach of the [input selectors] you provide will be called with all of the selector's arguments. You can add additional input selectors to extract arguments and forward them to the [result function], like this:\r\n\r\n```ts\r\nconst selectTodosByCategory = createSelector(\r\n  (state: RootState) => state.todos,\r\n  // Extract the second argument to pass it on\r\n  (state: RootState, category: string) => category,\r\n  (todos, category) => todos.filter(t => t.category === category)\r\n)\r\n```\r\n\r\n<details><summary><b>Detailed Explanation: Selectors and Arguments</b></summary>\r\n\r\nWhen creating a selector that accepts arguments in Reselect, it's important to structure your input and [output selector]s appropriately. Here are key points to consider:\r\n\r\n1. **Consistency in Arguments**: Ensure that all positional arguments across [input selectors] are of the same type for consistency.\r\n\r\n2. **Selective Argument Usage**: Design each selector to use only its relevant argument(s) and ignore the rest. This is crucial because all [input selectors] receive the same arguments that are passed to the [output selector].\r\n\r\nSuppose we have the following state structure:\r\n\r\n```ts\r\ninterface RootState {\r\n  items: {\r\n    id: number\r\n    category: string\r\n    vendor: { id: number; name: string }\r\n  }[]\r\n  // ... other state properties ...\r\n}\r\n```\r\n\r\nTo create a selector that filters `items` based on a `category` and excludes a specific `id`, you can set up your selectors as follows:\r\n\r\n```ts\r\nconst selectAvailableItems = createSelector(\r\n  [\r\n    // First input selector extracts items from the state\r\n    (state: RootState) => state.items,\r\n    // Second input selector forwards the category argument\r\n    (state: RootState, category: string) => category,\r\n    // Third input selector forwards the ID argument\r\n    (state: RootState, category: string, id: number) => id\r\n  ],\r\n  // Output selector uses the extracted items, category, and ID\r\n  (items, category, id) =>\r\n    items.filter(item => item.category === category && item.id !== id)\r\n)\r\n```\r\n\r\nInternally Reselect is doing this:\r\n\r\n```ts\r\n// Input selector #1\r\nconst items = (state: RootState, category: string, id: number) => state.items\r\n// Input selector #2\r\nconst category = (state: RootState, category: string, id: number) => category\r\n// Input selector #3\r\nconst id = (state: RootState, category: string, id: number) => id\r\n// result of output selector\r\nconst finalResult =\r\n  // The result function\r\n  items.filter(item => item.category === category && item.id !== id)\r\n```\r\n\r\nIn this example, `selectItemId` expects that its second argument will be some simple value, while `selectVendorName` expects that the second argument is an object. If you call `selectItemById(state, 42)`, `selectVendorName` will break because it's trying to access `42.name`. Reselect's TS types should detect this and prevent compilation:\r\n\r\n```ts\r\nconst selectItems = (state: RootState) => state.items\r\n\r\n// expects a number as the second argument\r\nconst selectItemId = (state: RootState, itemId: number) => itemId\r\n\r\n// expects an object as the second argument\r\nconst selectVendorName = (\r\n  state: RootState,\r\n  vendor: { id: number; name: string }\r\n) => vendor.name\r\n\r\nconst selectItemById = createSelector(\r\n  [selectItems, selectItemId, selectVendorName],\r\n  (items, itemId, vendorName) => items[itemId]\r\n)\r\n```\r\n\r\n</details>\r\n\r\n### Can the memoization behavior be customized?\r\n\r\nYes. The built-in `defaultMemoize` memoizer works great for a lot of use cases, but it can be customized or swapped out for a different memoizer. See [these examples](#customize-equalitycheck-for-defaultmemoize).\r\n\r\n### How do I test a selector?\r\n\r\nSelectors are pure functions - for a given input, a selector should always produce the same result. For this reason they are simple to unit test: call the selector with a set of inputs, and assert that the result value matches an expected shape.\r\n\r\n<details><summary><b>Detailed Explanation: Testing Selectors</b></summary>\r\n\r\n```ts\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\nconst state: RootState = {\r\n  todos: [\r\n    { id: 0, completed: false },\r\n    { id: 1, completed: true }\r\n  ],\r\n  alerts: [\r\n    { id: 0, read: false },\r\n    { id: 1, read: true }\r\n  ]\r\n}\r\n\r\n// With `Vitest` or `Jest`\r\ntest('selector unit test', () => {\r\n  const selectTodoIds = createSelector(\r\n    [(state: RootState) => state.todos],\r\n    todos => todos.map(({ id }) => id)\r\n  )\r\n  const firstResult = selectTodoIds(state)\r\n  const secondResult = selectTodoIds(state)\r\n  // Reference equality should pass.\r\n  expect(firstResult).toBe(secondResult)\r\n  // Deep equality should also pass.\r\n  expect(firstResult).toStrictEqual(secondResult)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  // The `Result Function` should not recalculate.\r\n  expect(selectTodoIds.recomputations()).toBe(1)\r\n  // `input selectors` should not recalculate.\r\n  expect(selectTodoIds.dependencyRecomputations()).toBe(1)\r\n})\r\n\r\n// With `Chai`\r\ntest('selector unit test', () => {\r\n  const selectTodoIds = createSelector(\r\n    [(state: RootState) => state.todos],\r\n    todos => todos.map(({ id }) => id)\r\n  )\r\n  const firstResult = selectTodoIds(state)\r\n  const secondResult = selectTodoIds(state)\r\n  // Reference equality should pass.\r\n  expect(firstResult).to.equal(secondResult)\r\n  // Deep equality should also pass.\r\n  expect(firstResult).to.deep.equal(secondResult)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  // The `result function` should not recalculate.\r\n  expect(selectTodoIds.recomputations()).to.equal(1)\r\n  // `input selectors` should not recalculate.\r\n  expect(selectTodoIds.dependencyRecomputations()).to.equal(1)\r\n})\r\n```\r\n\r\n</details>\r\n\r\n### Can I share a selector across multiple component instances?\r\n\r\nYes, although if they pass in different arguments, you will need to handle that in order for memoization to work consistently:\r\n\r\n- Pass a larger `maxSize` if using `defaultMemoize` ( as of 4.1.0+)\r\n- Use [`weakMapMemoize`](#weakmapmemoize) (as of 5.0.0+)\r\n\r\n### Are there TypeScript Typings?\r\n\r\nYes! Reselect is now written in TypeScript itself, so they should Just Work™.\r\n\r\n### I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`\r\n\r\nStarting in 5.0.0 you should be able to nest up to 30 selectors, but in case you still run into this issue, you can refer to [this\r\ncomment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as\r\nrelating to nested selectors.\r\n\r\n### How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nSelectors that take arguments are commonly used inside of React-Redux's `useSelector` by using a closure to pass along the extra arguments:\r\n\r\n```ts\r\nfunction TodosList({ category }) {\r\n  const filteredTodos = useSelector(state =>\r\n    selectTodosByCategory(state, category)\r\n  )\r\n}\r\n```\r\n\r\nIf you prefer to use a curried form instead, you can create a curried selector with this recipe:\r\n\r\n<details><summary><b>Detailed Explanation: Creating Curried Selectors</b></summary>\r\n\r\nYou can try this pattern:\r\n\r\n```ts\r\nconst currySelector = <\r\n  State,\r\n  Result,\r\n  Params extends readonly any[],\r\n  AdditionalFields\r\n>(\r\n  selector: ((state: State, ...args: Params) => Result) & AdditionalFields\r\n) => {\r\n  const curriedSelector = (...args: Params) => {\r\n    return (state: State) => {\r\n      return selector(state, ...args)\r\n    }\r\n  }\r\n  return Object.assign(curriedSelector, selector)\r\n}\r\n\r\nconst selectTodoByIdCurried = currySelector(\r\n  createSelector(\r\n    [(state: RootState) => state.todos, (state: RootState, id: number) => id],\r\n    (todos, id) => todos.find(todo => todo.id === id)\r\n  )\r\n)\r\n```\r\n\r\nOr for reusability you can do this:\r\n\r\n```ts\r\nimport type { defaultMemoize, SelectorArray, UnknownMemoizer } from 'reselect'\r\nimport { createSelector } from 'reselect'\r\n\r\nexport const createCurriedSelector = <\r\n  InputSelectors extends SelectorArray,\r\n  Result,\r\n  OverrideMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,\r\n  OverrideArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize\r\n>(\r\n  ...args: Parameters<\r\n    typeof createSelector<\r\n      InputSelectors,\r\n      Result,\r\n      OverrideMemoizeFunction,\r\n      OverrideArgsMemoizeFunction\r\n    >\r\n  >\r\n) => {\r\n  return currySelector(createSelector(...args))\r\n}\r\n```\r\n\r\nThis:\r\n\r\n```ts\r\nconst selectTodoById = createSelector(\r\n  [(state: RootState) => state.todos, (state: RootState, id: number) => id],\r\n  (todos, id) => todos.find(todo => todo.id === id)\r\n)\r\n\r\nselectTodoById(state, 0)\r\n```\r\n\r\nIs the same as this:\r\n\r\n```ts\r\nselectTodoByIdCurried(0)(state)\r\n```\r\n\r\nAs before you had to do this:\r\n\r\n```ts\r\nconst todoById = useSelector(state => selectTodoById(state, id))\r\n```\r\n\r\nNow you can do this:\r\n\r\n```ts\r\nconst todoById = useSelector(selectTodoByIdCurried(id))\r\n```\r\n\r\nAnother thing you can do if you are using [React-Redux] is create a custom hook factory function:\r\n\r\n```ts\r\nimport { useSelector } from 'react-redux'\r\n\r\nexport const createParametricSelectorHook = <\r\n  Result,\r\n  Params extends readonly unknown[]\r\n>(\r\n  selector: (state: RootState, ...params: Params) => Result\r\n) => {\r\n  return (...args: Params) => {\r\n    return useSelector(state => selector(state, ...args))\r\n  }\r\n}\r\n\r\nconst useSelectTodo = createParametricSelectorHook(selectTodoById)\r\n```\r\n\r\nAnd then inside your component:\r\n\r\n```tsx\r\nimport type { FC } from 'react'\r\n\r\ninterface Props {\r\n  id: number\r\n}\r\n\r\nconst MyComponent: FC<Props> = ({ id }) => {\r\n  const todo = useSelectTodo(id)\r\n  return <div>{todo.title}</div>\r\n}\r\n```\r\n\r\n</details>\r\n\r\n### How can I make pre-typed version of [`createSelector`](#createselector) for my root state?\r\n\r\nWhen used with Redux, it's typical to have all input selectors take `(state: RootState)` as their first argument. Creating a pre-typed version of `createSelector` can shorten that repetition.\r\n\r\n<details><summary><b>Detailed Explanation: Pre-Typed `createSelector`</b></summary>\r\n\r\nYou can create a custom typed version of [`createSelector`] by defining a utility type that extends the original [`createSelector`] function. Here's an example:\r\n\r\n```ts\r\nimport type {\r\n  OutputSelector,\r\n  Selector,\r\n  SelectorArray,\r\n  UnknownMemoizer\r\n} from 'reselect'\r\nimport { createSelector } from 'reselect'\r\n\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\nexport type TypedCreateSelector<\r\n  State,\r\n  MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,\r\n  ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize\r\n> = <\r\n  InputSelectors extends readonly Selector<State>[],\r\n  Result,\r\n  OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,\r\n  OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction\r\n>(\r\n  ...createSelectorArgs: Parameters<\r\n    typeof createSelector<\r\n      InputSelectors,\r\n      Result,\r\n      OverrideMemoizeFunction,\r\n      OverrideArgsMemoizeFunction\r\n    >\r\n  >\r\n) => ReturnType<\r\n  typeof createSelector<\r\n    InputSelectors,\r\n    Result,\r\n    OverrideMemoizeFunction,\r\n    OverrideArgsMemoizeFunction\r\n  >\r\n>\r\n\r\nexport const createAppSelector: TypedCreateSelector<RootState> = createSelector\r\n```\r\n\r\n> [!WARNING]: This approach currently only supports [input selectors] provided as a single array.\r\n\r\n</details>\r\n\r\n### What if I want to use [`createSelector`](#createselector) without memoization?\r\n\r\nThere may be rare cases when you might want to use `createSelector` for its composition syntax, but without any memoization applied. In that case, create an [`identity function`][Identity Function] and use it as the memoizers:\r\n\r\n```ts\r\nconst identity = <Func extends (...args: any[]) => any>(func: Func) => func\r\n\r\nconst createNonMemoizedSelector = createSelectorCreator({\r\n  memoize: identity,\r\n  argsMemoize: identity\r\n})\r\n```\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## External References\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\n- [**`WeakMap`**][`WeakMap`]\r\n- [**`Reference Equality Check`**][Reference Equality Check]\r\n- [**`Memoization`**][Memoization]\r\n- [**`Identity Function`**][Identity Function]\r\n\r\n</details>\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping [`createSelector`] and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Prior Art and Inspiration\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[typescript-badge]: https://img.shields.io/badge/TypeScript-v4%2E7%2B-007ACC?style=for-the-badge&logo=TypeScript&logoColor=black&labelColor=blue&color=gray\r\n[build-badge]: https://img.shields.io/github/actions/workflow/status/reduxjs/reselect/build-and-test-types.yml?branch=master&style=for-the-badge\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=for-the-badge\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=for-the-badge\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n\r\n<!-- External Links -->\r\n\r\n[`WeakMap`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap 'WeakMap'\r\n[Reference Equality Check]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality 'Reference Equality Check'\r\n[Memoization]: https://en.wikipedia.org/wiki/Memoization 'Memoization'\r\n[Identity Function]: https://en.wikipedia.org/wiki/Identity_function 'Identity Function'\r\n[`useMemo`]: https://react.dev/reference/react/useMemo#usememo 'useMemo'\r\n[`useCallback`]: https://react.dev/reference/react/useCallback#usecallback 'useCallback'\r\n[`re-reselect`]: https://github.com/toomuchdesign/re-reselect 're-reselect'\r\n[Redux]: https://redux.js.org 'Redux'\r\n[React]: https://react.dev 'React'\r\n[React-Redux]: https://react-redux.js.org 'React-Redux'\r\n\r\n<!-- Internal Links -->\r\n\r\n[selector]: #selector-function 'Selector Function'\r\n[input selectors]: #input-selectors 'Input Selectors'\r\n[output selector]: #output-selector 'Output Selector'\r\n[result function]: #result-function 'Result Function'\r\n[`dependencies`]: #dependencies 'Dependencies'\r\n[**_Cascading Memoization_**]: #cascading-memoization 'Cascading Memoization'\r\n[output selector fields]: #output-selector-fields 'Output Selector Fields'\r\n[`createSelector`]: #createselectorinputselectors--inputselectors-resultfunc-createselectoroptions 'createSelector'\r\n[`createSelectorCreator`]: #createselectorcreatormemoize--options-memoizeoptions 'createSelectorCreator'\r\n[`defaultMemoize`]: #defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck 'defaultMemoize'\r\n[`weakMapMemoize`]: #weakmapmemoizefunc---since-500 'weakMapMemoize'\r\n[`unstable_autotrackMemoize`]: #unstable_autotrackmemoizefunc---since-500 'unstable_autotrackMemoize'\r\n[`createStructuredSelector`]: #createstructuredselector-inputSelectorsObject--selectorcreator--createselector 'createStructuredSelector'\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"4ebcf6631f80901ce1495f8a7c5164708532faed","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","bench":"vitest --run bench --mode production","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","type-check":"vitest --run typecheck","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json","type-check:trace":"vitest --run typecheck && tsc --noEmit -p typescript_test/tsconfig.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"9.8.1","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^6.7.0","jsdom":"^23.0.0","react":"^18.2.0","eslint":"^8.0.1","lodash":"^4.17.21","rimraf":"^3.0.2","vitest":"^0.34","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"5.2","memoize-one":"^6.0.0","react-redux":"^9.0.0-rc.0","@types/react":"^18.2.38","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^2.0.0-rc.1","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.26.1","@testing-library/react":"^14.1.2","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"^6","@typescript/analyze-trace":"^0.10.1","@typescript-eslint/eslint-plugin":"^6","@typescript-eslint/eslint-plugin-tslint":"^6"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0-rc.0_1701403584662_0.8084043082279722","host":"s3://npm-registry-packages"}},"5.0.0-rc.1":{"name":"reselect","version":"5.0.0-rc.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0-rc.1","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"931940d65793bef62850961cc4135b718062dc8e","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0-rc.1.tgz","fileCount":29,"integrity":"sha512-wj5aaS7l7IQRctxKcElF9ODmnl3qm2HLmes7UFam9pKxB/AsyDjWyRkTnExFrmjrS18mvXz1Gz/enqEPZcFs1w==","signatures":[{"sig":"MEYCIQDDNlJ60WeudBGS77dDZjF0uYStQJQZnx4gHvtWSWp3ZgIhAOkVkhXm1wqi1dzTHwItxv2agRDgLgKmWEraAZwQqrde","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":654689},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","readme":"# Reselect\r\n\r\n[![npm package][npm-badge]][npm][![Coveralls][coveralls-badge]][coveralls][![GitHub Workflow Status][build-badge]][build]![TypeScript][typescript-badge]\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing [Redux] to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with [React-Redux].\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to [Redux], it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```ts\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\n# NPM\r\nnpm install reselect\r\n\r\n# Yarn\r\nyarn add reselect\r\n\r\n# Bun\r\nbun add reselect\r\n\r\n# PNPM\r\npnpm add reselect\r\n```\r\n\r\n---\r\n\r\n## Basic Usage\r\n\r\nReselect exports a [`createSelector`] API, which generates memoized selector functions. [`createSelector`] accepts one or more [input selectors], which extract values from arguments, and a [result function] function that receives the extracted values and should return a derived value. If the generated [output selector] is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/reselect-example-g3k9gf?file=/src/index.js):\r\n\r\n```ts\r\nimport { createSelector } from 'reselect'\r\n\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\nconst state: RootState = {\r\n  todos: [\r\n    { id: 0, completed: false },\r\n    { id: 1, completed: true }\r\n  ],\r\n  alerts: [\r\n    { id: 0, read: false },\r\n    { id: 1, read: true }\r\n  ]\r\n}\r\n\r\nconst selectCompletedTodos = (state: RootState) => {\r\n  console.log('selector ran')\r\n  return state.todos.filter(todo => todo.completed === true)\r\n}\r\n\r\nselectCompletedTodos(state) // selector ran\r\nselectCompletedTodos(state) // selector ran\r\nselectCompletedTodos(state) // selector ran\r\n\r\nconst memoizedSelectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => {\r\n    console.log('memoized selector ran')\r\n    return todos.filter(todo => todo.completed === true)\r\n  }\r\n)\r\n\r\nmemoizedSelectCompletedTodos(state) // memoized selector ran\r\nmemoizedSelectCompletedTodos(state)\r\nmemoizedSelectCompletedTodos(state)\r\n\r\nconsole.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false\r\n\r\nconsole.log(\r\n  memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)\r\n) //=> true\r\n```\r\n\r\nAs you can see from the example above, `memoizedSelectCompletedTodos` does not run the second or third time, but we still get the same return value as last time.\r\n\r\nIn addition to skipping unnecessary recalculations, `memoizedSelectCompletedTodos` returns the existing result reference if there is no recalculation. This is important for libraries like [React-Redux] or [React] that often rely on reference equality checks to optimize UI updates.\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n  - [Redux Toolkit](#redux-toolkit)\r\n  - [Standalone](#standalone)\r\n- [Basic Usage](#basic-usage)\r\n- [Terminology](#terminology)\r\n- [How Does Reselect Work?](#how-does-reselect-work)\r\n  - [Cascading Memoization](#cascading-memoization)\r\n  - [Why Reselect Is Often Used With Redux](#why-reselect-is-often-used-with-redux)\r\n- [API](#api)\r\n  - [**`createSelector`**][`createSelector`]\r\n  - [**`createSelectorCreator`**][`createSelectorCreator`]\r\n  - [**`createStructuredSelector`**][`createStructuredSelector`]\r\n  - [**`lruMemoize`**][`lruMemoize`]\r\n  - [**`weakMapMemoize`**][`weakMapMemoize`]\r\n  - [**`unstable_autotrackMemoize`**][`unstable_autotrackMemoize`]\r\n- [Debugging Tools](#debuggingtools)\r\n  - [Development-Only Stability Checks](#development-only-stability-checks)\r\n  - [Output Selector Fields](#output-selector-fields)\r\n- [What's New in 5.0.0?](#v5summary)\r\n- [Optimizing Reselect](#optimizing-reselect)\r\n- [FAQ](#faq)\r\n  - [Why isn’t my selector recomputing when the input state changes?](#why-isnt-my-selector-recomputing-when-the-input-state-changes)\r\n  - [Why is my selector recomputing when the input state stays the same?](#why-is-my-selector-recomputing-when-the-input-state-stays-the-same)\r\n  - [Can I use Reselect without Redux?](#can-i-use-reselect-without-redux)\r\n  - [How do I create a selector that takes an argument?](#how-do-i-create-a-selector-that-takes-an-argument)\r\n  - [Can the memoization behavior be customized?](#can-the-memoization-behavior-be-customized)\r\n  - [How do I test a selector?](#how-do-i-test-a-selector)\r\n  - [Can I share a selector across multiple component instances?](#can-i-share-a-selector-across-multiple-component-instances)\r\n  - [Are there TypeScript Typings?](#are-there-typescript-typings)\r\n  - [I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`](#i-am-seeing-a-typescript-error-type-instantiation-is-excessively-deep-and-possibly-infinite)\r\n  - [How can I make a curried selector?](#how-can-i-make-a-curried-selector)\r\n  - [How can I make pre-typed version of `createSelector` for my root state?](#how-can-i-make-pre-typed-version-of-createselector-for-my-root-state)\r\n  - [What if I want to use `createSelector` without memoization?](#what-if-i-want-to-use-createselector-without-memoization)\r\n- [External References](#external-references)\r\n- [Related Projects](#related-projects)\r\n- [License](#license)\r\n- [Prior Art and Inspiration](#prior-art-and-inspiration)\r\n\r\n---\r\n\r\n## Terminology\r\n\r\n- <a name=\"selector-function\"></a>[**Selector Function**](#selector-function): A function that accepts one or more JavaScript values as arguments, and derives a result. When used with [Redux], the first argument is typically the entire Redux store state.\r\n- <a name=\"input-selectors\"></a>[**input selectors**](#input-selectors): Basic selector functions used as building blocks for creating a memoized selector. They are passed as the first argument(s) to [`createSelector`], and are called with all selector arguments. They are responsible for extracting and providing necessary values to the [result function].\r\n- <a name=\"output-selector\"></a>[**Output Selector**](#output-selector): The actual memoized selectors created by [`createSelector`].\r\n- <a name=\"result-function\"></a>[**Result Function**](#result-function): The function that comes after the [input selectors]. It takes the [input selectors]' return values as arguments and returns a result.\r\n- <a name=\"dependencies\"></a>[**`Dependencies`**](#dependencies): Same as [input selectors]. They are what the [output selector] \"depends\" on.\r\n\r\nThe below example serves as a visual aid:\r\n\r\n```ts\r\nconst outputSelector = createSelector(\r\n  [inputSelector1, inputSelector2, inputSelector3], // synonymous with `dependencies`.\r\n  resultFunc // Result function\r\n)\r\n```\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## How Does Reselect Work?\r\n\r\nReselect, at its core, is a library for creating memoized selectors in JavaScript applications. Its primary role is to efficiently compute derived data based on provided inputs. A key aspect of Reselect's internal mechanism is how it orchestrates the flow of arguments from the final selector to its constituent [input selectors].\r\n\r\n```ts\r\nconst finalSelector = (...args) => {\r\n  const extractedValues = inputSelectors.map(inputSelector =>\r\n    inputSelector(...args)\r\n  )\r\n  return resultFunc(...extractedValues)\r\n}\r\n```\r\n\r\nIn this pattern, the `finalSelector` is composed of several [input selectors], **all receiving the same arguments as the final selector**. Each input selector processes its part of the data, and the results are then combined and further processed by the [result function]. Understanding this argument flow is crucial for appreciating how Reselect optimizes data computation and minimizes unnecessary recalculations.\r\n\r\n<a id=\"cascadingmemoization\"></a>\r\n\r\n### Cascading Memoization\r\n\r\nReselect uses a two-stage \"cascading\" approach to memoizing functions:\r\n\r\n<details><summary><b>Detailed Explanation: Cascading Memoization</b></summary>\r\n\r\nThe way Reselect works can be broken down into multiple parts:\r\n\r\n1. **Initial Run**: On the first call, Reselect runs all the [input selectors], gathers their results, and passes them to the [result function].\r\n\r\n2. **Subsequent Runs**: For subsequent calls, Reselect performs two levels of checks:\r\n\r\n   - **First Level**: It compares the current arguments with the previous ones (done by `argsMemoize`).\r\n\r\n     - If they're the same, it returns the cached result without running the [input selectors] or the [result function].\r\n\r\n     - If they differ, it proceeds (\"cascades\") to the second level.\r\n\r\n   - **Second Level**: It runs the [input selectors] and compares their current results with the previous ones (done by `memoize`).\r\n     > [!NOTE]\r\n     > If any one of the [input selectors] return a different result, all [input selectors] will recalculate.\r\n     - If the results are the same, it returns the cached result without running the [result function].\r\n     - If the results differ, it runs the [result function].\r\n\r\nThis behavior is what we call **_Cascading Double-Layer Memoization_**.\r\n\r\n#### Reselect Vs Standard Memoization\r\n\r\n##### Standard Memoization\r\n\r\n![normal-memoization-function](docs/assets//normal-memoization-function.png)\r\n\r\n_Standard memoization only compares arguments. If they're the same, it returns the cached result._\r\n\r\n##### Memoization with Reselect\r\n\r\n![reselect-memoization](docs/assets//reselect-memoization.png)\r\n\r\n_Reselect adds a second layer of checks with the [input selectors]. This is crucial in [Redux] applications where state references change frequently._\r\n\r\nA normal [memoization] function will compare the arguments, and if they are the same as last time, it will skip running the function and return the cached result. However, Reselect enhances this by introducing a second tier of checks via its [input selectors]. It's possible that the arguments passed to these [input selectors] may change, yet their results remain the same. When this occurs, Reselect avoids re-executing the [result function], and returns the cached result.\r\n\r\nThis feature becomes crucial in [Redux] applications, where the `state` changes its reference anytime an `action` is dispatched.\r\n\r\n> [!NOTE]\r\n> The [input selectors] take the same arguments as the [output selector].\r\n\r\n</details>\r\n\r\n### Why Reselect Is Often Used With [Redux]\r\n\r\nWhile Reselect can be used independently from Redux, it is a standard tool used in most Redux applications to help optimize calculations and UI updates:\r\n\r\n<details><summary><b>Detailed Explanation: Reselect and Redux Optimization</b></summary>\r\n\r\nImagine you have a selector like this:\r\n\r\n```ts\r\nconst selectCompletedTodos = (state: RootState) =>\r\n  state.todos.filter(todo => todo.completed === true)\r\n```\r\n\r\nSo you decide to memoize it:\r\n\r\n```ts\r\nconst selectCompletedTodos = someMemoizeFunction((state: RootState) =>\r\n  state.todos.filter(todo => todo.completed === true)\r\n)\r\n```\r\n\r\nThen you update `state.alerts`:\r\n\r\n```ts\r\nstore.dispatch(toggleRead(0))\r\n```\r\n\r\nNow when you call `selectCompletedTodos`, it re-runs, because we have effectively broken memoization.\r\n\r\n```ts\r\nselectCompletedTodos(store.getState())\r\n// Will not run, and the cached result will be returned.\r\nselectCompletedTodos(store.getState())\r\nstore.dispatch(toggleRead(0))\r\n// It recalculates.\r\nselectCompletedTodos(store.getState())\r\n```\r\n\r\nBut why? `selectCompletedTodos` only needs to access `state.todos`, and has nothing to do with `state.alerts`, so why have we broken memoization? Well that's because in [Redux] anytime you make a change to the root `state`, it gets shallowly updated, which means its reference changes, therefore a normal memoization function will always fail the comparison check on the arguments.\r\n\r\nBut with Reselect, we can do something like this:\r\n\r\n```ts\r\nconst selectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.filter(todo => todo.completed === true)\r\n)\r\n```\r\n\r\nAnd now we have achieved memoization:\r\n\r\n```ts\r\nselectCompletedTodos(store.getState())\r\n// Will not run, and the cached result will be returned.\r\nselectCompletedTodos(store.getState())\r\nstore.dispatch(toggleRead(0))\r\n// The `input selectors` will run, but the `result function` is\r\n// skipped and the cached result will be returned.\r\nselectCompletedTodos(store.getState())\r\n```\r\n\r\nEven when the overall `state` changes, Reselect ensures efficient memoization through its unique approach. The [result function] doesn't re-run if the relevant part of the `state` (in this case `state.todos`), remains unchanged. This is due to Reselect's [**_Cascading Double-Layer Memoization_**][**_Cascading Memoization_**]. The first layer checks the entire `state`, and the second layer checks the results of the [input selectors]. If the first layer fails (due to a change in the overall `state`) but the second layer succeeds (because `state.todos` is unchanged), Reselect skips recalculating the [result function]. This dual-check mechanism makes Reselect particularly effective in [Redux] applications, ensuring computations are only done when truly necessary.\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## API\r\n\r\n<a id=\"createselector\"></a>\r\n\r\n### createSelector(...inputSelectors | [inputSelectors], resultFunc, createSelectorOptions?)\r\n\r\n<b>Description</b>\r\n\r\nAccepts one or more \"[input selectors]\" (either as separate arguments or a single array),\r\na single \"[result function]\", and an optional options object, and\r\ngenerates a memoized selector function.\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                     | Description                                                                       |\r\n| :----------------------- | :-------------------------------------------------------------------------------- |\r\n| `inputSelectors`         | An array of [input selectors], can also be passed as separate arguments.          |\r\n| `resultFunc`             | A function that takes the results of the [input selectors] as separate arguments. |\r\n| `createSelectorOptions?` | An optional options object that allows for further customization per selector.    |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized [output selector].\r\n\r\n<details><summary><b>Type Parameters</b></summary>\r\n\r\n| Name                          | Description                                                                                                                                                                                            |\r\n| :---------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `InputSelectors`              | The type of the [input selectors] array.                                                                                                                                                               |\r\n| `Result`                      | The return type of the [result function] as well as the [output selector].                                                                                                                             |\r\n| `OverrideMemoizeFunction`     | The type of the optional `memoize` function that could be passed into the options object to override the original `memoize` function that was initially passed into [`createSelectorCreator`].         |\r\n| `OverrideArgsMemoizeFunction` | The type of the optional `argsMemoize` function that could be passed into the options object to override the original `argsMemoize` function that was initially passed into [`createSelectorCreator`]. |\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"createselectorcreator\" ></a>\r\n\r\n### createSelectorCreator(memoize | options, ...memoizeOptions)\r\n\r\n<b>Description</b>\r\n\r\nAccepts either a `memoize` function and `...memoizeOptions` rest parameter, or since 5.0.0 an `options` object containing a `memoize` function and creates a custom selector creator function.\r\n\r\n<b>Parameters (since 5.0.0)</b>\r\n\r\n| Name                           | Description                                                                                                                                                                                                                                                                                                         |\r\n| :----------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\r\n| `options`                      | An options object containing the `memoize` function responsible for memoizing the `resultFunc` inside [`createSelector`] (e.g., `lruMemoize` or `weakMapMemoize`). It also provides additional options for customizing memoization. While the `memoize` property is mandatory, the rest are optional.           |\r\n| `options.argsMemoize?`         | The optional memoize function that is used to memoize the arguments passed into the [output selector] generated by [`createSelector`] (e.g., `lruMemoize` or `weakMapMemoize`). <br /> **`Default`** `weakMapMemoize`                                                                                           |\r\n| `options.argsMemoizeOptions?`  | Optional configuration options for the `argsMemoize` function. These options are passed to the `argsMemoize` function as the second argument. <br /> since 5.0.0                                                                                                                                                    |\r\n| `options.devModeChecks?` | Overrides the settings for the global development mode checks for the selector. <br /> since 5.0.0 |\r\n| `options.memoize`              | The memoize function that is used to memoize the `resultFunc` inside [`createSelector`] (e.g., `lruMemoize` or `weakMapMemoize`). since 5.0.0                                                                                                                                                                   |\r\n| `options.memoizeOptions?`      | Optional configuration options for the `memoize` function. These options are passed to the `memoize` function as the second argument. <br /> since 5.0.0                                                                                                                                                            |\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                        | Description                                                                                                                                        |\r\n| :-------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `memoize`                   | The `memoize` function responsible for memoizing the `resultFunc` inside [`createSelector`] (e.g., `lruMemoize` or `weakMapMemoize`).              |\r\n| `...memoizeOptionsFromArgs` | Optional configuration options for the memoization function. These options are then passed to the memoize function as the second argument onwards. |\r\n\r\n<b>Returns</b>\r\n\r\nA customized [`createSelector`] function.\r\n\r\n<details><summary><b>Type Parameters</b></summary>\r\n\r\n| Name                  | Description                                                                                                                                                                                                                                                |\r\n| :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `MemoizeFunction`     | The type of the memoize function that is used to memoize the `resultFunc` inside [`createSelector`] (e.g., `lruMemoize` or `weakMapMemoize`).                                                                                                              |\r\n| `ArgsMemoizeFunction` | The type of the optional memoize function that is used to memoize the arguments passed into the [output selector] generated by [`createSelector`] (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n##### Using `options` (since 5.0.0)\r\n\r\n```ts\r\nconst customCreateSelector = createSelectorCreator({\r\n  memoize: customMemoize, // Function to be used to memoize `resultFunc`\r\n  memoizeOptions: [memoizeOption1, memoizeOption2], // Options passed to `customMemoize` as the second argument onwards\r\n  argsMemoize: customArgsMemoize, // Function to be used to memoize the selector's arguments\r\n  argsMemoizeOptions: [argsMemoizeOption1, argsMemoizeOption2] // Options passed to `customArgsMemoize` as the second argument onwards\r\n})\r\n\r\nconst customSelector = customCreateSelector(\r\n  [inputSelector1, inputSelector2],\r\n  resultFunc // `resultFunc` will be passed as the first argument to `customMemoize`\r\n)\r\n\r\ncustomSelector(\r\n  ...selectorArgs // Will be memoized by `customArgsMemoize`\r\n)\r\n```\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n##### Using `memoize` and `...memoizeOptions`\r\n\r\n`createSelectorCreator` can be used to make a customized version of [`createSelector`].\r\n\r\nThe `memoize` argument is a memoization function to replace `weakMapMemoize`.\r\n\r\nThe `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:\r\n\r\n```ts\r\nconst customSelectorCreator = createSelectorCreator(\r\n  customMemoize, // Function to be used to memoize `resultFunc`\r\n  option1, // `option1` will be passed as second argument to `customMemoize`\r\n  option2, // `option2` will be passed as third argument to `customMemoize`\r\n  option3 // `option3` will be passed as fourth argument to `customMemoize`\r\n)\r\n\r\nconst customSelector = customSelectorCreator(\r\n  [inputSelector1, inputSelector2],\r\n  resultFunc // `resultFunc` will be passed as first argument to `customMemoize`\r\n)\r\n```\r\n\r\nInternally `customSelector` calls the memoize function as follows:\r\n\r\n```ts\r\ncustomMemoize(resultFunc, option1, option2, option3)\r\n```\r\n\r\n##### Additional Examples\r\n\r\n###### Customize `equalityCheck` for `lruMemoize`\r\n\r\n```js\r\nimport { createSelectorCreator, lruMemoize } from 'reselect'\r\nimport isEqual from 'lodash.isequal'\r\n\r\n// create a \"selector creator\" that uses lodash.isequal instead of ===\r\nconst createDeepEqualSelector = createSelectorCreator(lruMemoize, isEqual)\r\n\r\n// use the new \"selector creator\" to create a selector\r\nconst selectSum = createDeepEqualSelector(\r\n  [state => state.values.filter(val => val < 5)],\r\n  values => values.reduce((acc, val) => acc + val, 0)\r\n)\r\n```\r\n\r\n###### Use memoize function from Lodash for an unbounded cache\r\n\r\n```js\r\nimport { createSelectorCreator } from 'reselect'\r\nimport memoize from 'lodash.memoize'\r\n\r\nconst hashFn = (...args) =>\r\n  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')\r\n\r\nconst customSelectorCreator = createSelectorCreator(memoize, hashFn)\r\n\r\nconst selector = customSelectorCreator(\r\n  [state => state.a, state => state.b],\r\n  (a, b) => a + b\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"createstructuredselector\"></a>\r\n\r\n### createStructuredSelector({ inputSelectorsObject }, selectorCreator = createSelector)\r\n\r\n<b>Description</b>\r\n\r\nA convenience function that simplifies returning an object made up of selector results.\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                   | Description                                                            |\r\n| :--------------------- | :--------------------------------------------------------------------- |\r\n| `inputSelectorsObject` | A key value pair consisting of input selectors.                        |\r\n| `selectorCreator?`     | A custom selector creator function. It defaults to [`createSelector`]. |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized structured selector.\r\n\r\n<details><summary><b>Type Parameters</b></summary>\r\n\r\n| Name                   | Description                                                                                                                                                   |\r\n| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ |\r\n| `InputSelectorsObject` | The shape of the [input selectors] object.                                                                                                                    |\r\n| `MemoizeFunction`      | The type of the memoize function that is used to create the structured selector. It defaults to `weakMapMemoize`.                                             |\r\n| `ArgsMemoizeFunction`  | The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `weakMapMemoize`. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n##### Modern Use Case\r\n\r\n```ts\r\nimport { createSelector, createStructuredSelector } from 'reselect'\r\n\r\ninterface RootState {\r\n  todos: {\r\n    id: number\r\n    completed: boolean\r\n    title: string\r\n    description: string\r\n  }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\n// This:\r\nconst structuredSelector = createStructuredSelector(\r\n  {\r\n    todos: (state: RootState) => state.todos,\r\n    alerts: (state: RootState) => state.alerts,\r\n    todoById: (state: RootState, id: number) => state.todos[id]\r\n  },\r\n  createSelector\r\n)\r\n\r\n// Is essentially the same as this:\r\nconst selector = createSelector(\r\n  [\r\n    (state: RootState) => state.todos,\r\n    (state: RootState) => state.alerts,\r\n    (state: RootState, id: number) => state.todos[id]\r\n  ],\r\n  (todos, alerts, todoById) => {\r\n    return {\r\n      todos,\r\n      alerts,\r\n      todoById\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nIn your component:\r\n\r\n```tsx\r\ninterface Props {\r\n  id: number\r\n}\r\n\r\nconst MyComponent: FC<Props> = ({ id }) => {\r\n  const { todos, alerts, todoById } = useSelector(state =>\r\n    structuredSelector(state, id)\r\n  )\r\n\r\n  return (\r\n    <div>\r\n      Next to do is:\r\n      <h2>{todoById.title}</h2>\r\n      <p>Description: {todoById.description}</p>\r\n      <ul>\r\n        <h3>All other to dos:</h3>\r\n        {todos.map(todo => (\r\n          <li key={todo.id}>{todo.title}</li>\r\n        ))}\r\n      </ul>\r\n    </div>\r\n  )\r\n}\r\n```\r\n\r\n##### Simple Use Case\r\n\r\n```ts\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\n// The result function in the following selector\r\n// is simply building an object from the input selectors\r\nconst structuredSelector = createSelector(selectA, selectB, (a, b) => ({\r\n  a,\r\n  b\r\n}))\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\n`createStructuredSelector` takes an object whose properties are input selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectorsObject` argument, but with the selectors replaced with their values.\r\n\r\n```ts\r\nconst selectA = state => state.a\r\nconst selectB = state => state.b\r\n\r\nconst structuredSelector = createStructuredSelector({\r\n  x: selectA,\r\n  y: selectB\r\n})\r\n\r\nconst result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }\r\n```\r\n\r\nStructured selectors can be nested:\r\n\r\n```ts\r\nconst nestedSelector = createStructuredSelector({\r\n  subA: createStructuredSelector({\r\n    selectorA,\r\n    selectorB\r\n  }),\r\n  subB: createStructuredSelector({\r\n    selectorC,\r\n    selectorD\r\n  })\r\n})\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n### Memoization Functions\r\n\r\nReselect comes with a selection of memoization functions, each uniquely designed to address different scenarios and performance requirements. By effectively leveraging these functions, you can significantly enhance the efficiency and responsiveness of your applications.\r\n\r\n<a id=\"lrumemoize\"></a>\r\n\r\n#### lruMemoize(func, equalityCheckOrOptions = referenceEqualityCheck)\r\n\r\n<b>Description</b>\r\n\r\nThe standard memoize function used by [`createSelector`].\r\n\r\nIt has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (since 4.1.0).\r\n\r\nIt determines if an argument has changed by calling the `equalityCheck` function. As `lruMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using [reference equality][Reference Equality Check]:\r\n\r\n```ts\r\nconst referenceEqualityCheck = (previousValue: any, currentValue: any) => {\r\n  return previousValue === currentValue\r\n}\r\n```\r\n\r\n<b>Parameters</b>\r\n\r\n| Name                     | Description                                                 |\r\n| :----------------------- | :---------------------------------------------------------- |\r\n| `func`                   | The function to be memoized.                                |\r\n| `equalityCheckOrOptions` | Either an `equality check` function or an `options` object. |\r\n\r\nSince 4.1.0, `lruMemoize` also accepts an options object as its first argument instead of an `equalityCheck` function. The `options` object may contain:\r\n\r\n```ts\r\ntype EqualityFn = (a: any, b: any) => boolean\r\n\r\ninterface LruMemoizeOptions {\r\n  equalityCheck?: EqualityFn\r\n  resultEqualityCheck?: EqualityFn\r\n  maxSize?: number\r\n}\r\n```\r\n\r\n| Name                  | Description                                                                                                                                                                                                                                                                                                                                                                         |\r\n| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `equalityCheck`       | Used to compare the individual arguments of the provided calculation function. <br /> **`Default`** = `referenceEqualityCheck`                                                                                                                                                                                                                                                        |\r\n| `resultEqualityCheck` | If provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This addresses the common <code>todos.map(todo => todo.id)</code> use case, where an update to another field in the original data causes a recalculation due to changed references, but the output is still effectively the same. |\r\n| `maxSize`             | The cache size for the selector. If greater than 1, the selector will use an LRU cache internally. <br /> **`Default`** = 1                                                                                                                                                                                                                                                         |\r\n\r\n> [!WARNING]\r\n> If `resultEqualityCheck` is used inside `argsMemoizeOptions` it has no effect.\r\n\r\n<b>Returns</b>\r\n\r\nA memoized function with a `.clearCache()` method attached.\r\n\r\n<details><summary><b>Type Parameters</b></summary>\r\n\r\n| Name   | Description                                |\r\n| :----- | :----------------------------------------- |\r\n| `Func` | The type of the function that is memoized. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n###### Using `lruMemoize` with [`createSelector`]\r\n\r\n```ts\r\nimport { shallowEqual } from 'react-redux'\r\nimport { createSelector } from 'reselect'\r\n\r\nconst selectTodoIds = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id),\r\n  {\r\n    memoizeOptions: {\r\n      equalityCheck: shallowEqual,\r\n      resultEqualityCheck: shallowEqual,\r\n      maxSize: 10\r\n    },\r\n    argsMemoizeOptions: {\r\n      equalityCheck: shallowEqual,\r\n      resultEqualityCheck: shallowEqual,\r\n      maxSize: 10\r\n    }\r\n  }\r\n)\r\n```\r\n\r\n###### Using `lruMemoize` with [`createSelectorCreator`]\r\n\r\n```ts\r\nimport { shallowEqual } from 'react-redux'\r\nimport { createSelectorCreator, lruMemoize } from 'reselect'\r\n\r\nconst createSelectorShallowEqual = createSelectorCreator({\r\n  memoize: lruMemoize,\r\n  memoizeOptions: {\r\n    equalityCheck: shallowEqual,\r\n    resultEqualityCheck: shallowEqual,\r\n    maxSize: 10\r\n  },\r\n  argsMemoize: lruMemoize,\r\n  argsMemoizeOptions: {\r\n    equalityCheck: shallowEqual,\r\n    resultEqualityCheck: shallowEqual,\r\n    maxSize: 10\r\n  }\r\n})\r\n\r\nconst selectTodoIds = createSelectorShallowEqual(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id)\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"weakmapmemoize\"></a>\r\n\r\n#### weakMapMemoize(func) - (since 5.0.0)\r\n\r\n<b>Description</b>\r\n\r\n[`lruMemoize`] has to be explicitly configured to have a cache size larger than 1, and uses an LRU cache internally.\r\n\r\n`weakMapMemoize` creates a tree of [`WeakMap`]-based cache nodes based on the identity of the arguments it's been called with (in this case, the extracted values from your input selectors). **This allows `weakMapMemoize` to have an effectively infinite cache size**. Cache results will be kept in memory as long as references to the arguments still exist, and then cleared out as the arguments are garbage-collected.\r\n\r\n<details><summary><b>Design Tradeoffs</b></summary>\r\n\r\n- Pros:\r\n\r\n  - It has an effectively infinite cache size, but you have no control over\r\n    how long values are kept in cache as it's based on garbage collection and [`WeakMap`]s.\r\n\r\n- Cons:\r\n  - There's currently no way to alter the argument comparisons. They're based on [strict reference equality][Reference Equality Check].\r\n\r\n</details>\r\n\r\n<details><summary><b>Use Cases</b></summary>\r\n\r\n- This memoizer is likely best used for cases where you need to call the\r\n  same selector instance with many different arguments, such as a single\r\n  selector instance that is used in a list item component and called with\r\n  item IDs like:\r\n\r\n```ts\r\nuseSelector(state => selectSomeData(state, id))\r\n```\r\n\r\nPrior to `weakMapMemoize`, you had this problem:\r\n\r\n```ts\r\ninterface RootState {\r\n  items: { id: number; category: string; name: string }[]\r\n}\r\n\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics') // Selector runs again!\r\n```\r\n\r\nBefore you could solve this in a number of different ways:\r\n\r\n1. Set the `maxSize` with [`lruMemoize`]:\r\n\r\n```ts\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category),\r\n  {\r\n    memoizeOptions: {\r\n      maxSize: 10\r\n    }\r\n  }\r\n)\r\n```\r\n\r\nBut this required having to know the cache size ahead of time.\r\n\r\n2. Create unique selector instances using [`useMemo`].\r\n\r\n```tsx\r\nconst makeSelectItemsByCategory = (category: string) =>\r\n  createSelector([(state: RootState) => state.items], items =>\r\n    items.filter(item => item.category === category)\r\n  )\r\n\r\ninterface Props {\r\n  category: string\r\n}\r\n\r\nconst MyComponent: FC<Props> = ({ category }) => {\r\n  const selectItemsByCategory = useMemo(\r\n    () => makeSelectItemsByCategory(category),\r\n    [category]\r\n  )\r\n\r\n  const itemsByCategory = useSelector(selectItemsByCategory)\r\n\r\n  return (\r\n    <div>\r\n      {itemsByCategory.map(item => (\r\n        <div key={item.id}>{item.name}</div>\r\n      ))}\r\n    </div>\r\n  )\r\n}\r\n```\r\n\r\n3. Using [`useCallback`].\r\n\r\n```tsx\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n\r\nconst MyComponent: FC<Props> = ({ category }) => {\r\n  const selectItemsByCategoryMemoized = useCallback(selectItemsByCategory, [])\r\n\r\n  const itemsByCategory = useSelector(state =>\r\n    selectItemsByCategoryMemoized(state, category)\r\n  )\r\n\r\n  return (\r\n    <div>\r\n      {itemsByCategory.map(item => (\r\n        <div key={item.id}>{item.name}</div>\r\n      ))}\r\n    </div>\r\n  )\r\n}\r\n```\r\n\r\n4. Use [`re-reselect`]:\r\n\r\n```ts\r\nimport { createCachedSelector } from 're-reselect'\r\n\r\nconst selectItemsByCategory = createCachedSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)((state: RootState, category: string) => category)\r\n```\r\n\r\nStarting in 5.0.0, you can eliminate this problem using `weakMapMemoize`.\r\n\r\n```ts\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category),\r\n  {\r\n    memoize: weakMapMemoize,\r\n    argsMemoize: weakMapMemoize\r\n  }\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics') // Cached\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics') // Still cached!\r\n```\r\n\r\nThis solves the problem of having to know and set the cache size prior to creating a memoized selector. Because `weakMapMemoize` essentially provides a dynamic cache size out of the box.\r\n\r\n</details>\r\n\r\n<b>Parameters</b>\r\n\r\n| Name   | Description                  |\r\n| :----- | :--------------------------- |\r\n| `func` | The function to be memoized. |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized function with a `.clearCache()` method attached.\r\n\r\n<details><summary><b>Type Parameters</b></summary>\r\n\r\n| Name   | Description                                |\r\n| :----- | :----------------------------------------- |\r\n| `Func` | The type of the function that is memoized. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n###### Using `weakMapMemoize` with [`createSelector`]\r\n\r\n```ts\r\nimport { createSelector, weakMapMemoize } from 'reselect'\r\n\r\nconst selectItemsByCategory = createSelector(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category),\r\n  {\r\n    memoize: weakMapMemoize,\r\n    argsMemoize: weakMapMemoize\r\n  }\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\n```\r\n\r\n###### Using `weakMapMemoize` with [`createSelectorCreator`]\r\n\r\n```ts\r\nimport { createSelectorCreator, weakMapMemoize } from 'reselect'\r\n\r\nconst createSelectorWeakMap = createSelectorCreator({\r\n  memoize: weakMapMemoize,\r\n  argsMemoize: weakMapMemoize\r\n})\r\n\r\nconst selectItemsByCategory = createSelectorWeakMap(\r\n  [\r\n    (state: RootState) => state.items,\r\n    (state: RootState, category: string) => category\r\n  ],\r\n  (items, category) => items.filter(item => item.category === category)\r\n)\r\n\r\nselectItemsByCategory(state, 'Electronics') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\nselectItemsByCategory(state, 'Stationery') // Selector runs\r\nselectItemsByCategory(state, 'Electronics')\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"unstable_autotrackMemoize\"></a>\r\n\r\n#### unstable_autotrackMemoize(func) - (since 5.0.0)\r\n\r\n<b>Description</b>\r\n\r\nUses an \"auto-tracking\" approach inspired by the work of the Ember Glimmer team. It uses a Proxy to wrap arguments and track accesses to nested fields in your selector on first read. Later, when the selector is called with new arguments, it identifies which accessed fields have changed and only recalculates the result if one or more of those accessed fields have changed. This allows it to be more precise than the shallow equality checks in `lruMemoize`.\r\n\r\n> [!WARNING]\r\n> This API is still experimental and undergoing testing.\r\n\r\n<details><summary><b>Design Tradeoffs</b></summary>\r\n\r\n- Pros:\r\n\r\n  - It is likely to avoid excess calculations and recalculate fewer times than `lruMemoize` will, which may also result in fewer component re-renders.\r\n\r\n- Cons:\r\n\r\n  - It only has a cache size of 1.\r\n  - It is slower than `lruMemoize`, because it has to do more work. (How much slower is dependent on the number of accessed fields in a selector, number of calls, frequency of input changes, etc)\r\n  - It can have some unexpected behavior. Because it tracks nested field accesses, cases where you don't access a field will not recalculate properly. For example, a badly-written selector like:\r\n\r\n  ```ts\r\n  createSelector([state => state.todos], todos => todos)\r\n  ```\r\n\r\n  that just immediately returns the extracted value will never update, because it doesn't see any field accesses to check.\r\n\r\n</details>\r\n\r\n<details><summary><b>Use Cases</b></summary>\r\n\r\n- It is likely best used for cases where you need to access specific nested fields in data, and avoid recalculating if other fields in the same data objects are immutably updated.\r\n\r\n</details>\r\n\r\n<b>Parameters</b>\r\n\r\n| Name   | Description                  |\r\n| :----- | :--------------------------- |\r\n| `func` | The function to be memoized. |\r\n\r\n<b>Returns</b>\r\n\r\nA memoized function with a `.clearCache()` method attached.\r\n\r\n<details><summary><b>Type Parameters</b></summary>\r\n\r\n| Name   | Description                                |\r\n| :----- | :----------------------------------------- |\r\n| `Func` | The type of the function that is memoized. |\r\n\r\n</details>\r\n\r\n<details><summary><b>Examples</b></summary>\r\n\r\n###### Using `unstable_autotrackMemoize` with [`createSelector`]\r\n\r\n```ts\r\nimport { unstable_autotrackMemoize, createSelector } from 'reselect'\r\n\r\nconst selectTodoIds = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id),\r\n  { memoize: unstable_autotrackMemoize }\r\n)\r\n```\r\n\r\n###### Using `unstable_autotrackMemoize` with [`createSelectorCreator`]\r\n\r\n```ts\r\nimport { unstable_autotrackMemoize, createSelectorCreator } from 'reselect'\r\n\r\nconst createSelectorAutotrack = createSelectorCreator({\r\n  memoize: unstable_autotrackMemoize\r\n})\r\n\r\nconst selectTodoIds = createSelectorAutotrack(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos.map(todo => todo.id)\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"debuggingtools\"></a>\r\n\r\n## Debugging Tools\r\n\r\n<a id=\"developmentonlychecks\"></a>\r\n\r\n### Development-Only Checks\r\n\r\nReselect includes extra checks in development mode to help catch and warn about mistakes in selector behavior.\r\n\r\n<a id=\"inputstabilitycheck\"></a>\r\n\r\n#### `inputStabilityCheck`\r\n\r\nDue to how [**_Cascading Memoization_**] works in Reselect, it is crucial that your [input selectors] do not return a new reference on each run. If an [input selector][input selectors] always returns a new reference, like\r\n\r\n```ts\r\nstate => ({ a: state.a, b: state.b })\r\n```\r\n\r\nor\r\n\r\n```ts\r\nstate => state.todos.map(todo => todo.id)\r\n```\r\n\r\nthat will cause the selector to never memoize properly.\r\nSince this is a common mistake, we've added a development mode check to catch this. By default, [`createSelector`] will now run the [input selectors] twice during the first call to the selector. If the result appears to be different for the same call, it will log a warning with the arguments and the two different sets of extracted input values.\r\n\r\n```ts\r\ntype DevModeCheckFrequency = 'always' | 'once' | 'never'\r\n```\r\n\r\n| Possible Values | Description                                     |\r\n| :-------------- | :---------------------------------------------- |\r\n| `once`          | Run only the first time the selector is called. |\r\n| `always`        | Run every time the selector is called.          |\r\n| `never`         | Never run the input stability check.            |\r\n\r\n> [!IMPORTANT]\r\n> The input stability check is automatically disabled in production environments.\r\n\r\nYou can configure this behavior in two ways:\r\n\r\n<a id=\"setglobaldevmodechecks\"></a>\r\n\r\n##### 1. Globally through `setGlobalDevModeChecks`:\r\n\r\nA `setGlobalDevModeChecks` function is exported from Reselect, which should be called with the desired setting.\r\n\r\n```ts\r\nimport { setGlobalDevModeChecks } from 'reselect'\r\n\r\n// Run only the first time the selector is called. (default)\r\nsetGlobalDevModeChecks({ inputStabilityCheck: 'once' })\r\n\r\n// Run every time the selector is called.\r\nsetGlobalDevModeChecks({ inputStabilityCheck: 'always' })\r\n\r\n// Never run the input stability check.\r\nsetGlobalDevModeChecks({ inputStabilityCheck: 'never' })\r\n```\r\n\r\n##### 2. Per selector by passing an `inputStabilityCheck` option directly to [`createSelector`]:\r\n\r\n```ts\r\n// Create a selector that double-checks the results of input selectors every time it runs.\r\nconst selectCompletedTodosLength = createSelector(\r\n  [\r\n    // ❌ Incorrect Use Case: This input selector will not be memoized properly since it always returns a new reference.\r\n    (state: RootState) =>\r\n      state.todos.filter(({ completed }) => completed === true)\r\n  ],\r\n  completedTodos => completedTodos.length,\r\n  // Will override the global setting.\r\n  { devModeChecks: { inputStabilityCheck: 'always' } }\r\n)\r\n```\r\n\r\n> [!WARNING]\r\n> This will override the global input stability check set by calling `setGlobalDevModeChecks`.\r\n\r\n<a id=\"identityfunctioncheck\"></a>\r\n\r\n#### `identityFunctionCheck`\r\n\r\nWhen working with Reselect, it's crucial to adhere to a fundamental philosophy regarding the separation of concerns between extraction and transformation logic.\r\n\r\n- **Extraction Logic**: This refers to operations like `state => state.todos`, which should be placed in [input selectors]. Extraction logic is responsible for retrieving or 'selecting' data from a broader state or dataset.\r\n\r\n- **Transformation Logic**: In contrast, transformation logic, such as `todos => todos.map(({ id }) => id)`, belongs in the [result function]. This is where you manipulate, format, or transform the data extracted by the input selectors.\r\n\r\nMost importantly, effective memoization in Reselect hinges on following these guidelines. Memoization, only functions correctly when extraction and transformation logic are properly segregated. By keeping extraction logic in input selectors and transformation logic in the result function, Reselect can efficiently determine when to reuse cached results and when to recompute them. This not only enhances performance but also ensures the consistency and predictability of your selectors.\r\n\r\nFor memoization to work as intended, it's imperative to follow both guidelines. If either is disregarded, memoization will not function properly. Consider the following example for clarity:\r\n\r\n```ts\r\n// ❌ Incorrect Use Case: This will not memoize correctly, and does nothing useful!\r\nconst brokenSelector = createSelector(\r\n  // ✔️ GOOD: Contains extraction logic.\r\n  [(state: RootState) => state.todos],\r\n  // ❌ BAD: Does not contain transformation logic.\r\n  todos => todos\r\n)\r\n```\r\n\r\n```ts\r\ntype DevModeCheckFrequency = 'always' | 'once' | 'never'\r\n```\r\n\r\n| Possible Values | Description                                     |\r\n| :-------------- | :---------------------------------------------- |\r\n| `once`          | Run only the first time the selector is called. |\r\n| `always`        | Run every time the selector is called.          |\r\n| `never`         | Never run the identity function check.          |\r\n\r\n> [!IMPORTANT]\r\n> The identity function check is automatically disabled in production environments.\r\n\r\nYou can configure this behavior in two ways:\r\n\r\n<a id=\"setGlobalDevModeChecks\"></a>\r\n\r\n##### 1. Globally through `setGlobalDevModeChecks`:\r\n\r\n```ts\r\nimport { setGlobalDevModeChecks } from 'reselect'\r\n\r\n// Run only the first time the selector is called. (default)\r\nsetGlobalDevModeChecks({ identityFunctionCheck: 'once' })\r\n\r\n// Run every time the selector is called.\r\nsetGlobalDevModeChecks({ identityFunctionCheck: 'always' })\r\n\r\n// Never run the identity function check.\r\nsetGlobalDevModeChecks({ identityFunctionCheck: 'never' })\r\n```\r\n\r\n##### 2. Per selector by passing an `identityFunctionCheck` option directly to [`createSelector`]:\r\n\r\n```ts\r\n// Create a selector that checks to see if the result function is an identity function.\r\nconst selectTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  // This result function does not contain any transformation logic.\r\n  todos => todos,\r\n  // Will override the global setting.\r\n  { devModeChecks: { identityFunctionCheck: 'always' } }\r\n)\r\n```\r\n\r\n<a id=\"outputselectorfields\"></a>\r\n\r\n### Output Selector Fields\r\n\r\nThe output selectors created by <code>createSelector</code> have several additional properties attached to them:\r\n\r\n| Name                            | Description                                                                                                                                                                                   |\r\n| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\r\n| `resultFunc`                    | The final function passed to [`createSelector`].                                                                                                                                              |\r\n| `memoizedResultFunc`            | The memoized version of `resultFunc`.                                                                                                                                                         |\r\n| `lastResult`                    | Returns the last result calculated by `memoizedResultFunc`.                                                                                                                                   |\r\n| `dependencies`                  | The array of the input selectors used by [`createSelector`] to compose `resultFunc`.                                                                                                          |\r\n| `recomputations`                | Counts the number of times `memoizedResultFunc` has been recalculated.                                                                                                                        |\r\n| `resetRecomputations`           | Resets the count of `recomputations` count to 0.                                                                                                                                              |\r\n| `dependencyRecomputations`      | Counts the number of times the [input selectors] ([`dependencies`]) have been recalculated. This is distinct from `recomputations`, which tracks the recalculations of the [result function]. |\r\n| `resetDependencyRecomputations` | Resets the `dependencyRecomputations` count to 0.                                                                                                                                             |\r\n| `memoize`                       | Function used to memoize the `resultFunc`.                                                                                                                                                    |\r\n| `argsMemoize`                   | Function used to memoize the arguments passed into the [output selector].                                                                                                                     |\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"v5summary\"></a>\r\n\r\n## What's New in 5.0.0?\r\n\r\nVersion 5.0.0 introduces several new features and improvements:\r\n\r\n- **Customization Enhancements**:\r\n\r\n  - Added the ability to pass an options object to [`createSelectorCreator`], allowing for customized `memoize` and `argsMemoize` functions, alongside their respective options (`memoizeOptions` and `argsMemoizeOptions`).\r\n  - The [`createSelector`] function now supports direct customization of `memoize` and `argsMemoize` within its options object.\r\n\r\n- **Memoization Functions**:\r\n\r\n  - Introduced new experimental memoization functions: `weakMapMemoize` and `unstable_autotrackMemoize`.\r\n  - Incorporated `memoize` and `argsMemoize` into the [output selector fields] for debugging purposes.\r\n\r\n- **TypeScript Support and Performance**:\r\n\r\n  - Discontinued support for TypeScript versions below 4.7, aligning with modern TypeScript features.\r\n  - Significantly improved TypeScript performance for nesting [output selector]s. The nesting limit has increased from approximately 8 to around 30 [output selector]s, greatly reducing the occurrence of the infamous `Type instantiation is excessively deep and possibly infinite` error.\r\n\r\n- **Selector API Enhancements**:\r\n\r\n  - Removed the second overload of `createStructuredSelector` due to its susceptibility to runtime errors.\r\n  - Added the `TypedStructuredSelectorCreator` utility type (_currently a work-in-progress_) to facilitate the creation of a pre-typed version of `createStructuredSelector` for your root state.\r\n\r\n- **Additional Functionalities**:\r\n\r\n  - Added `dependencyRecomputations` and `resetDependencyRecomputations` to the [output selector fields]. These additions provide greater control and insight over [input selectors], complementing the new `argsMemoize` API.\r\n  - Introduced `inputStabilityCheck`, a development tool that runs the [input selectors] twice using the same arguments and triggers a warning If they return differing results for the same call.\r\n  - Introduced `identityFunctionCheck`, a development tool that checks to see if the [result function] returns its own input.\r\n\r\nThese updates aim to enhance flexibility, performance, and developer experience. For detailed usage and examples, refer to the updated documentation sections for each feature.\r\n\r\n- **Breaking Changes**:\r\n\r\n  - Removed `ParametricSelector` and `OutputParametricSelector` types. Their functionalities are now integrated into `Selector` and `OutputSelector` respectively, which inherently support additional parameters.\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n<a id=\"optimizingreselect\"></a>\r\n\r\n## Optimizing Reselect\r\n\r\n### Common Mistakes\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nA somewhat common mistake is to write an [input selector][input selectors] that extracts a value or does some derivation, and a [result function] that just returns its result:\r\n\r\n```ts\r\n// ❌ BROKEN: this will not memoize correctly, and does nothing useful!\r\nconst brokenSelector = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => todos\r\n)\r\n```\r\n\r\nAny [result function] that just returns its inputs is incorrect! The [result function] should always have the transformation logic.\r\n\r\nSimilarly:\r\n\r\n```ts\r\n// ❌ BROKEN: this will not memoize correctly!\r\nconst brokenSelector = createSelector(\r\n  [(state: RootState) => state],\r\n  state => state.todos\r\n)\r\n```\r\n\r\n</details>\r\n\r\n### Handling Empty Array Results\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nTo reduce recalculations, use a predefined empty array when `array.filter` or similar methods result in an empty array.\r\n\r\nSo you can have a pattern like this:\r\n\r\n```ts\r\ninterface RootState {\r\n  todos: {\r\n    id: number\r\n    title: string\r\n    description: string\r\n    completed: boolean\r\n  }[]\r\n}\r\n\r\nconst EMPTY_ARRAY: [] = []\r\n\r\nconst selectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => {\r\n    const completedTodos = todos.filter(todo => todo.completed === true)\r\n    return completedTodos.length === 0 ? EMPTY_ARRAY : completedTodos\r\n  }\r\n)\r\n```\r\n\r\nOr to avoid repetition, you can create a wrapper function and reuse it:\r\n\r\n```ts\r\nconst EMPTY_ARRAY: [] = []\r\n\r\nexport const fallbackToEmptyArray = <T>(array: T[]) => {\r\n  return array.length === 0 ? EMPTY_ARRAY : array\r\n}\r\n\r\nconst selectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => {\r\n    return fallbackToEmptyArray(todos.filter(todo => todo.completed === true))\r\n  }\r\n)\r\n```\r\n\r\nThis way if the [result function] returns an empty array twice in a row, your component will not re-render due to a stable empty array reference:\r\n\r\n```ts\r\nconst completedTodos = selectCompletedTodos(store.getState())\r\n\r\nstore.dispatch(addTodo())\r\n\r\nconsole.log(completedTodos === selectCompletedTodos(store.getState())) //=> true\r\n```\r\n\r\n</details>\r\n\r\n### Best Practices\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nThere are a few details that will help you skip running as many functions as possible and get the best possible performance out of Reselect:\r\n\r\n- Due to the [**_Cascading Memoization_**] in Reselect, The first layer of checks is upon the arguments that are passed to the [output selector], therefore it's best to maintain the same reference for the arguments as much as possible.\r\n- In [Redux], your state will change reference when updated. But it's best to keep the additional arguments as simple as possible, you can pass in objects or array as long as their reference does not change. Or you can pass in primitives like numbers for ids.\r\n- Keep your [input selectors] as simple as possible. It's best if they mostly consist of field accessors like `state => state.todos` or argument providers like `(state, id) => id`. You should not be doing any sort of calculation inside [input selectors], and you should definitely not be returning an object or array with a new reference each time.\r\n- The [result function] is only re-run as a last resort. So make sure to put any and all calculations inside your [result function]. That way, Reselect will only run those calculations if all other checks fail.\r\n\r\nThis:\r\n\r\n```ts\r\n// ✔️ This is optimal because we have less calculations in input selectors and more in the result function.\r\nconst selectorGood = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => someExpensiveComputation(todos)\r\n)\r\n```\r\n\r\nIs preferable to this:\r\n\r\n```ts\r\n// ❌ This is not optimal!\r\nconst selectorBad = createSelector(\r\n  [(state: RootState) => someExpensiveComputation(state.todos)],\r\n  someOtherCalculation\r\n)\r\n```\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## FAQ\r\n\r\n### Why isn’t my selector recomputing when the input state changes?\r\n\r\nCheck that your memoization function is compatible with your state update function (i.e. the reducer if you are using [Redux]). For example, a selector created with [`createSelector`] will not work with a state update function that mutates an existing object instead of creating a new one each time. [`createSelector`] uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using [Redux], mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).\r\n\r\n### Why is my selector recomputing when the input state stays the same?\r\n\r\nTo address unexpected recomputations in your selector, first ensure that `inputStabilityCheck` is set to either `'always'` or `'once'`. This setting aids in debugging by monitoring the stability of your inputs. Additionally, utilize [output selector fields] such as `recomputations`, `resetRecomputations`, `dependencyRecomputations`, and `resetDependencyRecomputations`. These tools help identify the source of the issue.\r\n\r\nKeep an eye on the `dependencyRecomputations` count. If it increases while `recomputations` remains the same, it suggests that your arguments are changing references but your [input selectors] are stable which is typically the desired behavior.\r\n\r\n<details><summary><b>Detailed Explanation: Selector Recomputations</b></summary>\r\n\r\nTo delve deeper, you can determine which arguments are changing references too frequently by using the `argsMemoizeOptions` and `equalityCheck`. Consider the following example:\r\n\r\n```ts\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean; type: string }[]\r\n}\r\n\r\nconst selectAlertsByType = createSelector(\r\n  [\r\n    (state: RootState) => state.alerts,\r\n    (state: RootState, type: string) => type\r\n  ],\r\n  (alerts, type) => alerts.filter(todo => todo.type === type),\r\n  {\r\n    argsMemoizeOptions: {\r\n      // This will check the arguments passed to the output selector.\r\n      equalityCheck: (a, b) => {\r\n        if (a !== b) {\r\n          console.log('Changed argument:', a, 'to', b)\r\n        }\r\n        return a === b\r\n      }\r\n    }\r\n  }\r\n)\r\n```\r\n\r\n</details>\r\n\r\n### Can I use Reselect without [Redux]?\r\n\r\nYes. Reselect has no dependencies on any other package, so although it was designed to be used with [Redux] it can be used independently. It can be used with any plain JS data, such as typical [React] state values, as long as that data is being updated immutably.\r\n\r\n### How do I create a selector that takes an argument?\r\n\r\nEach of the [input selectors] you provide will be called with all of the selector's arguments. You can add additional input selectors to extract arguments and forward them to the [result function], like this:\r\n\r\n```ts\r\nconst selectTodosByCategory = createSelector(\r\n  (state: RootState) => state.todos,\r\n  // Extract the second argument to pass it on\r\n  (state: RootState, category: string) => category,\r\n  (todos, category) => todos.filter(t => t.category === category)\r\n)\r\n```\r\n\r\n<details><summary><b>Detailed Explanation: Selectors and Arguments</b></summary>\r\n\r\nWhen creating a selector that accepts arguments in Reselect, it's important to structure your input and [output selector]s appropriately. Here are key points to consider:\r\n\r\n1. **Consistency in Arguments**: Ensure that all positional arguments across [input selectors] are of the same type for consistency.\r\n\r\n2. **Selective Argument Usage**: Design each selector to use only its relevant argument(s) and ignore the rest. This is crucial because all [input selectors] receive the same arguments that are passed to the [output selector].\r\n\r\nSuppose we have the following state structure:\r\n\r\n```ts\r\ninterface RootState {\r\n  items: {\r\n    id: number\r\n    category: string\r\n    vendor: { id: number; name: string }\r\n  }[]\r\n  // ... other state properties ...\r\n}\r\n```\r\n\r\nTo create a selector that filters `items` based on a `category` and excludes a specific `id`, you can set up your selectors as follows:\r\n\r\n```ts\r\nconst selectAvailableItems = createSelector(\r\n  [\r\n    // First input selector extracts items from the state\r\n    (state: RootState) => state.items,\r\n    // Second input selector forwards the category argument\r\n    (state: RootState, category: string) => category,\r\n    // Third input selector forwards the ID argument\r\n    (state: RootState, category: string, id: number) => id\r\n  ],\r\n  // Output selector uses the extracted items, category, and ID\r\n  (items, category, id) =>\r\n    items.filter(item => item.category === category && item.id !== id)\r\n)\r\n```\r\n\r\nInternally Reselect is doing this:\r\n\r\n```ts\r\n// Input selector #1\r\nconst items = (state: RootState, category: string, id: number) => state.items\r\n// Input selector #2\r\nconst category = (state: RootState, category: string, id: number) => category\r\n// Input selector #3\r\nconst id = (state: RootState, category: string, id: number) => id\r\n// result of output selector\r\nconst finalResult =\r\n  // The result function\r\n  items.filter(item => item.category === category && item.id !== id)\r\n```\r\n\r\nIn this example, `selectItemId` expects that its second argument will be some simple value, while `selectVendorName` expects that the second argument is an object. If you call `selectItemById(state, 42)`, `selectVendorName` will break because it's trying to access `42.name`. Reselect's TS types should detect this and prevent compilation:\r\n\r\n```ts\r\nconst selectItems = (state: RootState) => state.items\r\n\r\n// expects a number as the second argument\r\nconst selectItemId = (state: RootState, itemId: number) => itemId\r\n\r\n// expects an object as the second argument\r\nconst selectVendorName = (\r\n  state: RootState,\r\n  vendor: { id: number; name: string }\r\n) => vendor.name\r\n\r\nconst selectItemById = createSelector(\r\n  [selectItems, selectItemId, selectVendorName],\r\n  (items, itemId, vendorName) => items[itemId]\r\n)\r\n```\r\n\r\n</details>\r\n\r\n### Can the memoization behavior be customized?\r\n\r\nYes. The built-in `lruMemoize` memoizer works great for a lot of use cases, but it can be customized or swapped out for a different memoizer. See [these examples](#customize-equalitycheck-for-lrumemoize).\r\n\r\n### How do I test a selector?\r\n\r\nSelectors are pure functions - for a given input, a selector should always produce the same result. For this reason they are simple to unit test: call the selector with a set of inputs, and assert that the result value matches an expected shape.\r\n\r\n<details><summary><b>Detailed Explanation: Testing Selectors</b></summary>\r\n\r\n```ts\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\nconst state: RootState = {\r\n  todos: [\r\n    { id: 0, completed: false },\r\n    { id: 1, completed: true }\r\n  ],\r\n  alerts: [\r\n    { id: 0, read: false },\r\n    { id: 1, read: true }\r\n  ]\r\n}\r\n\r\n// With `Vitest` or `Jest`\r\ntest('selector unit test', () => {\r\n  const selectTodoIds = createSelector(\r\n    [(state: RootState) => state.todos],\r\n    todos => todos.map(({ id }) => id)\r\n  )\r\n  const firstResult = selectTodoIds(state)\r\n  const secondResult = selectTodoIds(state)\r\n  // Reference equality should pass.\r\n  expect(firstResult).toBe(secondResult)\r\n  // Deep equality should also pass.\r\n  expect(firstResult).toStrictEqual(secondResult)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  // The result function should not recalculate.\r\n  expect(selectTodoIds.recomputations()).toBe(1)\r\n  // input selectors should not recalculate.\r\n  expect(selectTodoIds.dependencyRecomputations()).toBe(1)\r\n})\r\n\r\n// With `Chai`\r\ntest('selector unit test', () => {\r\n  const selectTodoIds = createSelector(\r\n    [(state: RootState) => state.todos],\r\n    todos => todos.map(({ id }) => id)\r\n  )\r\n  const firstResult = selectTodoIds(state)\r\n  const secondResult = selectTodoIds(state)\r\n  // Reference equality should pass.\r\n  expect(firstResult).to.equal(secondResult)\r\n  // Deep equality should also pass.\r\n  expect(firstResult).to.deep.equal(secondResult)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  selectTodoIds(state)\r\n  // The result function should not recalculate.\r\n  expect(selectTodoIds.recomputations()).to.equal(1)\r\n  // input selectors should not recalculate.\r\n  expect(selectTodoIds.dependencyRecomputations()).to.equal(1)\r\n})\r\n```\r\n\r\n</details>\r\n\r\n### Can I share a selector across multiple component instances?\r\n\r\nYes, although if they pass in different arguments, you will need to handle that in order for memoization to work consistently:\r\n\r\n- Pass a larger `maxSize` if using `lruMemoize` ( as of 4.1.0+)\r\n- Use [`weakMapMemoize`](#weakmapmemoize) (as of 5.0.0+)\r\n\r\n### Are there TypeScript Typings?\r\n\r\nYes! Reselect is now written in TypeScript itself, so they should Just Work™.\r\n\r\n### I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`\r\n\r\nStarting in 5.0.0 you should be able to nest up to 30 selectors, but in case you still run into this issue, you can refer to [this\r\ncomment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as\r\nrelating to nested selectors.\r\n\r\n### How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?\r\n\r\nSelectors that take arguments are commonly used inside of React-Redux's `useSelector` by using a closure to pass along the extra arguments:\r\n\r\n```ts\r\nfunction TodosList({ category }) {\r\n  const filteredTodos = useSelector(state =>\r\n    selectTodosByCategory(state, category)\r\n  )\r\n}\r\n```\r\n\r\nIf you prefer to use a curried form instead, you can create a curried selector with this recipe:\r\n\r\n<details><summary><b>Detailed Explanation: Creating Curried Selectors</b></summary>\r\n\r\n```ts\r\nconst currySelector = <\r\n  State,\r\n  Result,\r\n  Params extends readonly any[],\r\n  AdditionalFields\r\n>(\r\n  selector: ((state: State, ...args: Params) => Result) & AdditionalFields\r\n) => {\r\n  const curriedSelector = (...args: Params) => {\r\n    return (state: State) => {\r\n      return selector(state, ...args)\r\n    }\r\n  }\r\n  return Object.assign(curriedSelector, selector)\r\n}\r\n\r\nconst selectTodoByIdCurried = currySelector(\r\n  createSelector(\r\n    [(state: RootState) => state.todos, (state: RootState, id: number) => id],\r\n    (todos, id) => todos.find(todo => todo.id === id)\r\n  )\r\n)\r\n```\r\n\r\nOr for reusability you can do this:\r\n\r\n```ts\r\nimport type { weakMapMemoize, SelectorArray, UnknownMemoizer } from 'reselect'\r\nimport { createSelector } from 'reselect'\r\n\r\nexport const createCurriedSelector = <\r\n  InputSelectors extends SelectorArray,\r\n  Result,\r\n  OverrideMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,\r\n  OverrideArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize\r\n>(\r\n  ...args: Parameters<\r\n    typeof createSelector<\r\n      InputSelectors,\r\n      Result,\r\n      OverrideMemoizeFunction,\r\n      OverrideArgsMemoizeFunction\r\n    >\r\n  >\r\n) => {\r\n  return currySelector(createSelector(...args))\r\n}\r\n```\r\n\r\nThis:\r\n\r\n```ts\r\nconst selectTodoById = createSelector(\r\n  [(state: RootState) => state.todos, (state: RootState, id: number) => id],\r\n  (todos, id) => todos.find(todo => todo.id === id)\r\n)\r\n\r\nselectTodoById(state, 0)\r\n```\r\n\r\nIs the same as this:\r\n\r\n```ts\r\nselectTodoByIdCurried(0)(state)\r\n```\r\n\r\nAs before you had to do this:\r\n\r\n```ts\r\nconst todoById = useSelector(state => selectTodoById(state, id))\r\n```\r\n\r\nNow you can do this:\r\n\r\n```ts\r\nconst todoById = useSelector(selectTodoByIdCurried(id))\r\n```\r\n\r\nAnother thing you can do if you are using [React-Redux] is create a custom hook factory function:\r\n\r\n```ts\r\nimport { useSelector } from 'react-redux'\r\n\r\nexport const createParametricSelectorHook = <\r\n  Result,\r\n  Params extends readonly unknown[]\r\n>(\r\n  selector: (state: RootState, ...params: Params) => Result\r\n) => {\r\n  return (...args: Params) => {\r\n    return useSelector(state => selector(state, ...args))\r\n  }\r\n}\r\n\r\nconst useSelectTodo = createParametricSelectorHook(selectTodoById)\r\n```\r\n\r\nAnd then inside your component:\r\n\r\n```tsx\r\nimport type { FC } from 'react'\r\n\r\ninterface Props {\r\n  id: number\r\n}\r\n\r\nconst MyComponent: FC<Props> = ({ id }) => {\r\n  const todo = useSelectTodo(id)\r\n  return <div>{todo.title}</div>\r\n}\r\n```\r\n\r\n</details>\r\n\r\n### How can I make pre-typed version of [`createSelector`](#createselector) for my root state?\r\n\r\nWhen used with Redux, it's typical to have all input selectors take `(state: RootState)` as their first argument. Creating a pre-typed version of `createSelector` can shorten that repetition.\r\n\r\n<details><summary><b>Detailed Explanation: Pre-Typed `createSelector`</b></summary>\r\n\r\nYou can create a custom typed version of [`createSelector`] by defining a utility type that extends the original [`createSelector`] function. Here's an example:\r\n\r\n```ts\r\nimport type {\r\n  OutputSelector,\r\n  Selector,\r\n  SelectorArray,\r\n  UnknownMemoizer,\r\n  weakMapMemoize\r\n} from 'reselect'\r\nimport { createSelector } from 'reselect'\r\n\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\nexport type TypedCreateSelector<\r\n  State,\r\n  MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,\r\n  ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize\r\n> = <\r\n  InputSelectors extends readonly Selector<State>[],\r\n  Result,\r\n  OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,\r\n  OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction\r\n>(\r\n  ...createSelectorArgs: Parameters<\r\n    typeof createSelector<\r\n      InputSelectors,\r\n      Result,\r\n      OverrideMemoizeFunction,\r\n      OverrideArgsMemoizeFunction\r\n    >\r\n  >\r\n) => ReturnType<\r\n  typeof createSelector<\r\n    InputSelectors,\r\n    Result,\r\n    OverrideMemoizeFunction,\r\n    OverrideArgsMemoizeFunction\r\n  >\r\n>\r\n\r\nexport const createAppSelector: TypedCreateSelector<RootState> = createSelector\r\n```\r\n\r\n> [!WARNING]: This approach currently only supports [input selectors] provided as a single array.\r\n\r\n</details>\r\n\r\n### What if I want to use [`createSelector`](#createselector) without memoization?\r\n\r\nThere may be rare cases when you might want to use `createSelector` for its composition syntax, but without any memoization applied. In that case, create an [`identity function`][Identity Function] and use it as the memoizers:\r\n\r\n```ts\r\nconst identity = <Func extends (...args: any[]) => any>(func: Func) => func\r\n\r\nconst createNonMemoizedSelector = createSelectorCreator({\r\n  memoize: identity,\r\n  argsMemoize: identity\r\n})\r\n```\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## External References\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\n- [**`WeakMap`**][`WeakMap`]\r\n- [**`Reference Equality Check`**][Reference Equality Check]\r\n- [**`Memoization`**][Memoization]\r\n- [**`Identity Function`**][Identity Function]\r\n\r\n</details>\r\n\r\n## Related Projects\r\n\r\n### [re-reselect](https://github.com/toomuchdesign/re-reselect)\r\n\r\nEnhances Reselect selectors by wrapping [`createSelector`] and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.\r\n\r\nUseful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.\r\n\r\n### [reselect-tools](https://github.com/skortchmark9/reselect-tools)\r\n\r\n- Measure selector recomputations across the app and identify performance bottlenecks\r\n- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension\r\n- Statically export a JSON representation of your selector graph for further analysis\r\n\r\n### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)\r\n\r\n[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.\r\n\r\nInspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.\r\n\r\n- Selectors Recomputations count in live time across the App for identify performance bottlenecks\r\n- Highlight most recomputed selectors\r\n- Dependency Graph\r\n- Search by Selectors Graph\r\n- Selectors Inputs\r\n- Selectors Output (In case if selector not dependent from external arguments)\r\n- Shows \"Not Memoized (NM)\" selectors\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Prior Art and Inspiration\r\n\r\n<details><summary><b>Click to expand</b></summary>\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[typescript-badge]: https://img.shields.io/badge/TypeScript-v4%2E7%2B-007ACC?style=for-the-badge&logo=TypeScript&logoColor=black&labelColor=blue&color=gray\r\n[build-badge]: https://img.shields.io/github/actions/workflow/status/reduxjs/reselect/build-and-test-types.yml?branch=master&style=for-the-badge\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=for-the-badge\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=for-the-badge\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n\r\n<!-- External Links -->\r\n\r\n[`WeakMap`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap 'WeakMap'\r\n[Reference Equality Check]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality 'Reference Equality Check'\r\n[Memoization]: https://en.wikipedia.org/wiki/Memoization 'Memoization'\r\n[Identity Function]: https://en.wikipedia.org/wiki/Identity_function 'Identity Function'\r\n[`useMemo`]: https://react.dev/reference/react/useMemo#usememo 'useMemo'\r\n[`useCallback`]: https://react.dev/reference/react/useCallback#usecallback 'useCallback'\r\n[`re-reselect`]: https://github.com/toomuchdesign/re-reselect 're-reselect'\r\n[Redux]: https://redux.js.org 'Redux'\r\n[React]: https://react.dev 'React'\r\n[React-Redux]: https://react-redux.js.org 'React-Redux'\r\n\r\n<!-- Internal Links -->\r\n\r\n[selector]: #selector-function 'Selector Function'\r\n[input selectors]: #input-selectors 'Input Selectors'\r\n[output selector]: #output-selector 'Output Selector'\r\n[result function]: #result-function 'Result Function'\r\n[`dependencies`]: #dependencies 'Dependencies'\r\n[**_Cascading Memoization_**]: #cascading-memoization 'Cascading Memoization'\r\n[output selector fields]: #output-selector-fields 'Output Selector Fields'\r\n[`createSelector`]: #createselectorinputselectors--inputselectors-resultfunc-createselectoroptions 'createSelector'\r\n[`createSelectorCreator`]: #createselectorcreatormemoize--options-memoizeoptions 'createSelectorCreator'\r\n[`lruMemoize`]: #lrumemoizefunc-equalitycheckoroptions--referenceequalitycheck 'lruMemoize'\r\n[`weakMapMemoize`]: #weakmapmemoizefunc---since-500 'weakMapMemoize'\r\n[`unstable_autotrackMemoize`]: #unstable_autotrackmemoizefunc---since-500 'unstable_autotrackMemoize'\r\n[`createStructuredSelector`]: #createstructuredselector-inputSelectorsObject--selectorcreator--createselector 'createStructuredSelector'\r\n\r\n</details>\r\n\r\n<div align=\"right\">[ <a href=\"#table-of-contents\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"b7a1015366893ffd20c89867c4a055bd416342cf","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","bench":"vitest --run bench --mode production","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","docs:build":"yarn --cwd website build","docs:clear":"yarn --cwd website clear","docs:serve":"yarn --cwd website serve","docs:start":"yarn --cwd website start","test:watch":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js watch","type-check":"vitest --run typecheck","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json","type-check:trace":"vitest --run typecheck && tsc --noEmit -p typescript_test/tsconfig.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"9.8.1","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"18.18.2","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^6.7.0","jsdom":"^23.0.0","react":"^18.2.0","eslint":"^8.0.1","lodash":"^4.17.21","rimraf":"^3.0.2","vitest":"^0.34","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"5.2","memoize-one":"^6.0.0","react-redux":"^9.0.0-rc.0","@types/react":"^18.2.38","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^2.0.0-rc.1","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.26.1","netlify-plugin-cache":"^1.0.3","@testing-library/react":"^14.1.2","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"^6","@typescript/analyze-trace":"^0.10.1","@typescript-eslint/eslint-plugin":"^6","@typescript-eslint/eslint-plugin-tslint":"^6"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0-rc.1_1701489153000_0.8080394777376823","host":"s3://npm-registry-packages"}},"5.0.0":{"name":"reselect","version":"5.0.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"36344481f36b5852de3a862c51e2152c9c67b2d2","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.0.tgz","fileCount":29,"integrity":"sha512-8YRuy8VJoLZ2+qtfVylxMLQOpx7uPH9KPtgPNoSKFeYMmiKKrvRX7Z/E3ouHqrcWlLqfyzDY6WUD96dSUKk06A==","signatures":[{"sig":"MEQCIAN2aabQSm+NgnhUd5ZdKgqqYJ7n3WjVZYMdjJhbGrAXAiBt618zTFJRq2DJ3H8axWcn0eXyVyFlJBhcU46if6XAoQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":585666},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"3bf2ab45591b91ba4619a004f169e66afc162078","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","bench":"vitest --run bench --mode production","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","docs:build":"yarn --cwd website build","docs:clear":"yarn --cwd website clear","docs:serve":"yarn --cwd website serve","docs:start":"yarn --cwd website start","test:watch":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js watch","type-check":"vitest --run typecheck","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json","type-check:trace":"vitest --run typecheck && tsc --noEmit -p typescript_test/tsconfig.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"16.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^6.7.0","jsdom":"^23.0.0","react":"^18.2.0","eslint":"^8.0.1","lodash":"^4.17.21","rimraf":"^3.0.2","vitest":"^0.34","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"5.2","memoize-one":"^6.0.0","react-redux":"^9.0.0-rc.0","@types/react":"^18.2.38","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^2.0.0-rc.1","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.26.1","netlify-plugin-cache":"^1.0.3","@testing-library/react":"^14.1.2","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"^6","@typescript/analyze-trace":"^0.10.1","@typescript-eslint/eslint-plugin":"^6","@typescript-eslint/eslint-plugin-tslint":"^6"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.0_1701663674127_0.5707744032898798","host":"s3://npm-registry-packages"}},"5.0.1":{"name":"reselect","version":"5.0.1","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.0.1","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"587cdaaeb4e0e8927cff80ebe2bbef05f74b1648","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz","fileCount":29,"integrity":"sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==","signatures":[{"sig":"MEUCIAs6002QUJTSnIBaJhKDb/TUSF36n2gK0XMQQ4LMK0xXAiEAniDXhNb2uW/jhfsKbpF9CzbJczTG9vpnDaju40aJYJU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":586222},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"2a1e0554737457aa202804cf00b040d3fe8af5c0","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","bench":"vitest --run bench --mode production","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","docs:build":"yarn --cwd website build","docs:clear":"yarn --cwd website clear","docs:serve":"yarn --cwd website serve","docs:start":"yarn --cwd website start","test:watch":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js watch","type-check":"vitest --run typecheck","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json","type-check:trace":"vitest --run typecheck && tsc --noEmit -p typescript_test/tsconfig.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace"},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"8.4.0","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"16.14.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^6.7.0","jsdom":"^23.0.0","react":"^18.2.0","eslint":"^8.0.1","lodash":"^4.17.21","rimraf":"^3.0.2","vitest":"^0.34","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"5.2","memoize-one":"^6.0.0","react-redux":"^9.0.0-rc.0","@types/react":"^18.2.38","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^2.0.0-rc.1","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.26.1","netlify-plugin-cache":"^1.0.3","@testing-library/react":"^14.1.2","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"^6","@typescript/analyze-trace":"^0.10.1","@typescript-eslint/eslint-plugin":"^6","@typescript-eslint/eslint-plugin-tslint":"^6"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.0.1_1701697906111_0.2181188513473875","host":"s3://npm-registry-packages"}},"5.1.0":{"name":"reselect","version":"5.1.0","keywords":["react","redux"],"license":"MIT","_id":"reselect@5.1.0","maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"contributors":[{"url":"https://github.com/ellbee","name":"Lee Bannard","email":"l_bannard@yahoo.co.uk"},{"url":"https://github.com/faassen","name":"Martijn Faassen"},{"url":"https://github.com/ianks","name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com"},{"url":"https://github.com/SpainTrain","name":"Mike S"},{"url":"https://github.com/omnidan","name":"Daniel Bugl","email":"me@omnidan.net"},{"url":"https://github.com/ryanatkn","name":"Ryan"},{"url":"https://github.com/HeyImAlex","name":"Alex Guerra","email":"alex@heyimalex.com"},{"url":"https://github.com/speedskater","name":"speedskater"},{"url":"https://github.com/sericaia","name":"Daniela Borges"},{"url":"https://github.com/existentialism","name":"Brian Ng","email":"bng412@gmail.com"},{"url":"https://github.com/chentsulin","name":"C. T. Lin","email":"chentsulin@gmail.com"},{"url":"https://github.com/chungchiehlun","name":"Jay","email":"wuceh14678@gmail.com"},{"url":"https://github.com/madebyherzblut","name":"Christian Schuhmann"},{"url":"https://github.com/volrath","name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com"},{"url":"https://github.com/ifunk","name":"Adam Royle"},{"url":"https://github.com/elliotcm","name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com"},{"url":"https://github.com/frankwallis","name":"frankwallis"},{"url":"https://github.com/kaddopur","name":"Jason Huang","email":"chaoju.huang@gmail.com"},{"url":"https://github.com/joshkel","name":"Josh Kelley"},{"url":"https://github.com/leonaves","name":"Leon Aves"},{"url":"https://github.com/markdalgleish","name":"Mark Dalgleish"},{"url":"https://github.com/chromakode","name":"Max Goodman","email":"c@chromako.de"},{"url":"https://github.com/weblancaster","name":"Michael Lancaster","email":"michaell.llancaster@gmail.com"},{"url":"https://github.com/zalmoxisus","name":"Mihail Diordiev"},{"url":"https://github.com/PSpSynedra","name":"PSpSynedra"},{"url":"https://github.com/SimenB","name":"Simen Bekkhus","email":"sbekkhus91@gmail.com"},{"url":"https://github.com/WadePeterson","name":"Wade Peterson"},{"url":"https://github.com/ambar","name":"长天之云","email":"ambar.lee@gmail.com"},{"url":"https://github.com/courthead","name":"Courtland Allen","email":"csallen@alum.mit.edu"},{"url":"https://github.com/HenrikJoreteg","name":"Henrik Joreteg","email":"henrik@joreteg.com"},{"url":"https://github.com/kyldvs","name":"Kyle Davis"},{"url":"https://github.com/clickclickonsal","name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com"},{"url":"https://github.com/npbee","name":"Nick Ball"},{"url":"https://github.com/mctep","name":"mctep"},{"url":"https://github.com/jacobrask","name":"Jacob Rask","email":"jacob@jacobrask.net"},{"url":"https://github.com/luqmaan","name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/matthetherington","name":"Matthew Hetherington"},{"url":"https://github.com/mjw56","name":"Mike Wilcox","email":"mwilcox56@gmail.com"},{"url":"https://github.com/threehams","name":"David Edmondson"},{"url":"https://github.com/zandroid","name":"Andrey Zaytsev","email":"za@zalab.net"},{"url":"https://github.com/1ven","name":"1ven"},{"url":"https://github.com/alexesdev","name":"Alexey Yurchenko","email":"alexes.dev@gmail.com"},{"url":"https://github.com/dpwrussell","name":"Douglas Russell"},{"url":"https://github.com/yoni-tock","name":"Yonatan Kogan"},{"url":"https://github.com/pesho","name":"Peter Petrov"},{"url":"https://github.com/wbreakell","name":"Walter Breakell"},{"url":"https://github.com/madeinfree","name":"Whien","email":"sal95610@gmail.com"},{"url":"https://github.com/bsideup","name":"Sergei Egorov","email":"bsideup@gmail.com"},{"url":"https://github.com/jimbolla","name":"Jim Bolla"},{"url":"https://github.com/carlbernrdo","name":"Carl Bernardo"},{"url":"https://github.com/aikoven","name":"Daniel Lytkin","email":"dan.lytkin@gmail.com"},{"url":"https://github.com/johnhaley81","name":"John Haley","email":"john@haley.io"},{"url":"https://github.com/alex3165","name":"Alexandre","email":"alexr.3165@gmail.com"}],"homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"dist":{"shasum":"c479139ab9dd91be4d9c764a7f3868210ef8cd21","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz","fileCount":29,"integrity":"sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==","signatures":[{"sig":"MEYCIQC4PqlEWZDy5xeBkYyzNxSCh8ADuVxtoERvXlTVo7qG5wIhAMoojtIEb3SO5iIIcbt3+rvlQ1g9VXNSOOwYRQBQ4rM0","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/reselect@5.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":623038},"main":"./dist/cjs/reselect.cjs","types":"./dist/reselect.d.ts","module":"./dist/reselect.legacy-esm.js","authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"exports":{".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"},"./package.json":"./package.json"},"gitHead":"21b0f4b3826afeb092b7b0bff099c7344af902a5","scripts":{"lint":"eslint src test","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run","bench":"vitest --run bench --mode production","build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","prepack":"yarn build","test:cov":"vitest run --coverage","docs:build":"yarn --cwd website build","docs:clear":"yarn --cwd website clear","docs:serve":"yarn --cwd website serve","docs:start":"yarn --cwd website start","test:watch":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js watch","type-check":"vitest --run --typecheck","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json","type-check:trace":"vitest --run --typecheck && tsc --noEmit -p typescript_test/tsconfig.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace"},"_npmUser":{"name":"eskimojo","email":"ben.j.durrant@gmail.com"},"repository":{"url":"git+https://github.com/reduxjs/reselect.git","type":"git"},"_npmVersion":"10.2.3","description":"Selectors for Redux.","directories":{},"sideEffects":false,"_nodeVersion":"18.19.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^6.7.0","jsdom":"^23.0.0","react":"^18.2.0","eslint":"^8.0.1","lodash":"^4.17.21","rimraf":"^3.0.2","vitest":"^1.1.1","shelljs":"^0.8.5","prettier":"^2.7.1","react-dom":"^18.2.0","typescript":"5.2","memoize-one":"^6.0.0","react-redux":"^9.0.4","@types/react":"^18.2.38","@types/lodash":"^4.14.175","micro-memoize":"^4.0.9","@types/shelljs":"^0.8.11","lodash.memoize":"^4.1.2","@reduxjs/toolkit":"^2.0.1","@types/react-dom":"^18.2.17","eslint-plugin-react":"^7.26.1","netlify-plugin-cache":"^1.0.3","@testing-library/react":"^14.1.2","eslint-plugin-typescript":"0.14.0","@typescript-eslint/parser":"^6","@typescript/analyze-trace":"^0.10.1","@typescript-eslint/eslint-plugin":"^6","@typescript-eslint/eslint-plugin-tslint":"^6"},"_npmOperationalInternal":{"tmp":"tmp/reselect_5.1.0_1704454566394_0.20099523875213166","host":"s3://npm-registry-packages"}},"5.1.1":{"name":"reselect","version":"5.1.1","description":"Selectors for Redux.","main":"./dist/cjs/reselect.cjs","module":"./dist/reselect.legacy-esm.js","types":"./dist/reselect.d.ts","exports":{"./package.json":"./package.json",".":{"types":"./dist/reselect.d.ts","import":"./dist/reselect.mjs","default":"./dist/cjs/reselect.cjs"}},"sideEffects":false,"bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"scripts":{"build":"tsup","clean":"rimraf dist","format":"prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"","lint":"eslint src test","prepack":"yarn build","bench":"vitest --run bench --mode production","test":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js --run && vitest --run --typecheck.only","test:watch":"node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js --watch","test:cov":"vitest run --coverage","type-check":"vitest --run --typecheck.only","type-check:trace":"vitest --run --typecheck.only && tsc --noEmit -p typescript_test/tsconfig.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace","test:typescript":"tsc --noEmit -p typescript_test/tsconfig.json","docs:start":"yarn --cwd website start","docs:build":"yarn --cwd website build","docs:clear":"yarn --cwd website clear","docs:serve":"yarn --cwd website serve"},"keywords":["react","redux"],"authors":["Lee Bannard","Robert Binna","Martijn Faassen","Philip Spitzlinger"],"repository":{"type":"git","url":"git+https://github.com/reduxjs/reselect.git"},"license":"MIT","devDependencies":{"@reduxjs/toolkit":"^2.0.1","@testing-library/react":"^14.1.2","@types/lodash":"^4.14.175","@types/react":"^18.2.38","@types/react-dom":"^18.2.17","@types/shelljs":"^0.8.11","@typescript-eslint/eslint-plugin":"^6","@typescript-eslint/eslint-plugin-tslint":"^6","@typescript-eslint/parser":"^6","@typescript/analyze-trace":"^0.10.1","eslint":"^8.0.1","eslint-plugin-react":"^7.26.1","eslint-plugin-typescript":"0.14.0","jsdom":"^23.0.0","lodash":"^4.17.21","lodash.memoize":"^4.1.2","memoize-one":"^6.0.0","micro-memoize":"^4.0.9","netlify-plugin-cache":"^1.0.3","prettier":"^2.7.1","react":"^18.2.0","react-dom":"^18.2.0","react-redux":"^9.0.4","rimraf":"^3.0.2","shelljs":"^0.8.5","tsup":"^6.7.0","typescript":"^5.4.2","vitest":"^1.1.1"},"packageManager":"yarn@4.1.0","_id":"reselect@5.1.1","contributors":[{"name":"Lee Bannard","email":"l_bannard@yahoo.co.uk","url":"https://github.com/ellbee"},{"name":"Martijn Faassen","url":"https://github.com/faassen"},{"name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com","url":"https://github.com/ianks"},{"name":"Mike S","url":"https://github.com/SpainTrain"},{"name":"Daniel Bugl","email":"me@omnidan.net","url":"https://github.com/omnidan"},{"name":"Ryan","url":"https://github.com/ryanatkn"},{"name":"Alex Guerra","email":"alex@heyimalex.com","url":"https://github.com/HeyImAlex"},{"name":"speedskater","url":"https://github.com/speedskater"},{"name":"Daniela Borges","url":"https://github.com/sericaia"},{"name":"Brian Ng","email":"bng412@gmail.com","url":"https://github.com/existentialism"},{"name":"C. T. Lin","email":"chentsulin@gmail.com","url":"https://github.com/chentsulin"},{"name":"Jay","email":"wuceh14678@gmail.com","url":"https://github.com/chungchiehlun"},{"name":"Christian Schuhmann","url":"https://github.com/madebyherzblut"},{"name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com","url":"https://github.com/volrath"},{"name":"Adam Royle","url":"https://github.com/ifunk"},{"name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com","url":"https://github.com/elliotcm"},{"name":"frankwallis","url":"https://github.com/frankwallis"},{"name":"Jason Huang","email":"chaoju.huang@gmail.com","url":"https://github.com/kaddopur"},{"name":"Josh Kelley","url":"https://github.com/joshkel"},{"name":"Leon Aves","url":"https://github.com/leonaves"},{"name":"Mark Dalgleish","url":"https://github.com/markdalgleish"},{"name":"Max Goodman","email":"c@chromako.de","url":"https://github.com/chromakode"},{"name":"Michael Lancaster","email":"michaell.llancaster@gmail.com","url":"https://github.com/weblancaster"},{"name":"Mihail Diordiev","url":"https://github.com/zalmoxisus"},{"name":"PSpSynedra","url":"https://github.com/PSpSynedra"},{"name":"Simen Bekkhus","email":"sbekkhus91@gmail.com","url":"https://github.com/SimenB"},{"name":"Wade Peterson","url":"https://github.com/WadePeterson"},{"name":"长天之云","email":"ambar.lee@gmail.com","url":"https://github.com/ambar"},{"name":"Courtland Allen","email":"csallen@alum.mit.edu","url":"https://github.com/courthead"},{"name":"Henrik Joreteg","email":"henrik@joreteg.com","url":"https://github.com/HenrikJoreteg"},{"name":"Kyle Davis","url":"https://github.com/kyldvs"},{"name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com","url":"https://github.com/clickclickonsal"},{"name":"Nick Ball","url":"https://github.com/npbee"},{"name":"mctep","url":"https://github.com/mctep"},{"name":"Jacob Rask","email":"jacob@jacobrask.net","url":"https://github.com/jacobrask"},{"name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com","url":"https://github.com/luqmaan"},{"name":"Walter Breakell","url":"https://github.com/wbreakell"},{"name":"Matthew Hetherington","url":"https://github.com/matthetherington"},{"name":"Mike Wilcox","email":"mwilcox56@gmail.com","url":"https://github.com/mjw56"},{"name":"David Edmondson","url":"https://github.com/threehams"},{"name":"Andrey Zaytsev","email":"za@zalab.net","url":"https://github.com/zandroid"},{"name":"1ven","url":"https://github.com/1ven"},{"name":"Alexey Yurchenko","email":"alexes.dev@gmail.com","url":"https://github.com/alexesdev"},{"name":"Douglas Russell","url":"https://github.com/dpwrussell"},{"name":"Yonatan Kogan","url":"https://github.com/yoni-tock"},{"name":"Peter Petrov","url":"https://github.com/pesho"},{"name":"Walter Breakell","url":"https://github.com/wbreakell"},{"name":"Whien","email":"sal95610@gmail.com","url":"https://github.com/madeinfree"},{"name":"Sergei Egorov","email":"bsideup@gmail.com","url":"https://github.com/bsideup"},{"name":"Jim Bolla","url":"https://github.com/jimbolla"},{"name":"Carl Bernardo","url":"https://github.com/carlbernrdo"},{"name":"Daniel Lytkin","email":"dan.lytkin@gmail.com","url":"https://github.com/aikoven"},{"name":"John Haley","email":"john@haley.io","url":"https://github.com/johnhaley81"},{"name":"Alexandre","email":"alexr.3165@gmail.com","url":"https://github.com/alex3165"}],"gitHead":"649a63fff214e7a2cd26dad00302ca2df8a5cc7a","homepage":"https://github.com/reduxjs/reselect#readme","_nodeVersion":"18.18.2","_npmVersion":"9.8.1","dist":{"integrity":"sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==","shasum":"c766b1eb5d558291e5e550298adb0becc24bb72e","tarball":"https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz","fileCount":29,"unpackedSize":646106,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTEeiY1AQPO3x5Fw6DmrCgcJIkwm9EihDpXIjuuDVD+gIhAM4lUdJQ3x3OP1e2ZTj+TN5TRMNlHgdzCfJ4n1Rek+LX"}]},"_npmUser":{"name":"acemarke","email":"mark.erikson@gmail.com"},"directories":{},"maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/reselect_5.1.1_1717280165987_0.21453623277839107"},"_hasShrinkwrap":false}},"time":{"created":"2015-07-01T11:58:54.446Z","modified":"2024-06-01T22:16:06.450Z","0.0.1":"2015-07-01T11:58:54.446Z","0.0.2":"2015-07-21T09:20:47.076Z","1.0.0-alpha":"2015-09-01T20:12:18.940Z","1.0.0-alpha2":"2015-09-03T20:09:40.169Z","1.0.0":"2015-09-09T20:13:46.068Z","1.1.0":"2015-09-16T16:04:02.915Z","2.0.0":"2015-10-02T12:43:50.649Z","2.0.1":"2015-11-08T09:48:57.508Z","2.0.2":"2016-01-14T21:16:05.004Z","2.0.3":"2016-02-01T20:23:51.129Z","2.1.0":"2016-03-03T20:03:31.505Z","2.2.0":"2016-03-15T04:06:52.463Z","2.2.1":"2016-03-15T04:30:47.184Z","2.3.0":"2016-04-07T17:55:33.640Z","2.4.0":"2016-04-16T22:26:25.316Z","2.5.0":"2016-04-21T12:23:15.488Z","2.5.1":"2016-04-21T13:01:32.410Z","2.5.2":"2016-07-03T14:31:30.289Z","2.5.3":"2016-07-04T11:09:45.984Z","2.5.4":"2016-09-17T09:27:43.015Z","3.0.0-rc1":"2017-03-15T18:16:03.044Z","3.0.0-beta.1":"2017-03-15T18:32:33.995Z","3.0.0-rc":"2017-03-15T18:34:26.633Z","3.0.0":"2017-03-24T20:30:27.428Z","3.0.1":"2017-05-10T21:50:27.047Z","4.0.0-beta.1":"2018-06-28T18:53:48.340Z","4.0.0":"2018-09-30T11:39:17.055Z","4.1.0-alpha.0":"2021-10-16T22:27:10.812Z","4.1.0-alpha.1":"2021-10-17T21:57:42.670Z","4.1.0-alpha.2":"2021-10-20T02:51:13.476Z","4.1.0-beta.0":"2021-10-21T02:20:21.832Z","4.1.0-beta.1":"2021-10-21T03:20:10.851Z","4.1.0-beta.2":"2021-10-24T18:26:23.036Z","4.1.0":"2021-10-26T02:14:25.404Z","4.1.1":"2021-10-26T23:52:11.824Z","4.1.2":"2021-11-04T01:48:58.138Z","4.1.3":"2021-11-16T02:54:55.369Z","4.1.4":"2021-11-17T04:41:46.878Z","4.1.5":"2021-11-24T21:25:26.599Z","4.1.6":"2022-06-07T00:06:54.607Z","4.1.7":"2022-11-04T01:45:46.059Z","4.1.8":"2023-04-16T20:31:40.638Z","5.0.0-alpha.0":"2023-05-10T02:27:51.432Z","5.0.0-alpha.1":"2023-05-10T03:41:48.629Z","5.0.0-alpha.2":"2023-05-14T22:28:28.993Z","5.0.0-beta.0":"2023-10-28T20:39:42.444Z","5.0.0-beta.1":"2023-11-16T04:27:54.914Z","5.0.0-rc.0":"2023-12-01T04:06:24.952Z","5.0.0-rc.1":"2023-12-02T03:52:33.272Z","5.0.0":"2023-12-04T04:21:14.321Z","5.0.1":"2023-12-04T13:51:46.325Z","5.1.0":"2024-01-05T11:36:06.553Z","5.1.1":"2024-06-01T22:16:06.224Z"},"maintainers":[{"name":"gaearon","email":"dan.abramov@gmail.com"},{"name":"timdorr","email":"timdorr@timdorr.com"},{"name":"ellbee","email":"l_bannard@yahoo.co.uk"},{"name":"phryneas","email":"mail@lenzw.de"},{"name":"acemarke","email":"mark.erikson@gmail.com"},{"name":"eskimojo","email":"ben.j.durrant@gmail.com"}],"repository":{"type":"git","url":"git+https://github.com/reduxjs/reselect.git"},"keywords":["react","redux"],"license":"MIT","homepage":"https://github.com/reduxjs/reselect#readme","bugs":{"url":"https://github.com/reduxjs/reselect/issues"},"readme":"# Reselect\r\n\r\n[![npm package][npm-badge]][npm][![Coveralls][coveralls-badge]][coveralls][![GitHub Workflow Status][build-badge]][build]![TypeScript][typescript-badge]\r\n\r\nA library for creating memoized \"selector\" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.\r\n\r\n- Selectors can compute derived data, allowing [Redux] to store the minimal possible state.\r\n- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.\r\n- Selectors are composable. They can be used as input to other selectors.\r\n\r\nThe **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with [React-Redux].\r\n\r\n## Installation\r\n\r\n### Redux Toolkit\r\n\r\nWhile Reselect is not exclusive to [Redux], it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.\r\n\r\n```ts\r\nimport { createSelector } from '@reduxjs/toolkit'\r\n```\r\n\r\n### Standalone\r\n\r\nFor standalone usage, install the `reselect` package:\r\n\r\n```bash\r\n# NPM\r\nnpm install reselect\r\n\r\n# Yarn\r\nyarn add reselect\r\n```\r\n\r\n---\r\n\r\n## Documentation\r\n\r\nThe Reselect docs are available at **https://reselect.js.org**, and include usage guides and API references:\r\n\r\n- [**Introduction**](#https://reselect.js.org/introduction/getting-started)\r\n- [**How Does Reselect Work?**](#https://reselect.js.org/introduction/how-does-reselect-work)\r\n- **API Reference**:\r\n  - **[`createSelector`]**\r\n  - **[`createSelectorCreator`]**\r\n  - **[`createStructuredSelector`]**\r\n  - [**Development-Only Stability Checks**](#https://reselect.js.org/api/development-only-stability-checks)\r\n  - **[`lruMemoize`]**\r\n  - **[`weakMapMemoize`]**\r\n- [**FAQ**](#https://reselect.js.org/FAQ)\r\n\r\n## Basic Usage\r\n\r\nReselect exports a [`createSelector`] API, which generates memoized selector functions. [`createSelector`] accepts one or more [input selectors], which extract values from arguments, and a [result function] function that receives the extracted values and should return a derived value. If the generated [output selector] is called multiple times, the output will only be recalculated when the extracted values have changed.\r\n\r\nYou can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/reselect-example-g3k9gf?file=/src/index.js):\r\n\r\n```ts\r\nimport { createSelector } from 'reselect'\r\n\r\ninterface RootState {\r\n  todos: { id: number; completed: boolean }[]\r\n  alerts: { id: number; read: boolean }[]\r\n}\r\n\r\nconst state: RootState = {\r\n  todos: [\r\n    { id: 0, completed: false },\r\n    { id: 1, completed: true }\r\n  ],\r\n  alerts: [\r\n    { id: 0, read: false },\r\n    { id: 1, read: true }\r\n  ]\r\n}\r\n\r\nconst selectCompletedTodos = (state: RootState) => {\r\n  console.log('selector ran')\r\n  return state.todos.filter(todo => todo.completed === true)\r\n}\r\n\r\nselectCompletedTodos(state) // selector ran\r\nselectCompletedTodos(state) // selector ran\r\nselectCompletedTodos(state) // selector ran\r\n\r\nconst memoizedSelectCompletedTodos = createSelector(\r\n  [(state: RootState) => state.todos],\r\n  todos => {\r\n    console.log('memoized selector ran')\r\n    return todos.filter(todo => todo.completed === true)\r\n  }\r\n)\r\n\r\nmemoizedSelectCompletedTodos(state) // memoized selector ran\r\nmemoizedSelectCompletedTodos(state)\r\nmemoizedSelectCompletedTodos(state)\r\n\r\nconsole.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false\r\n\r\nconsole.log(\r\n  memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)\r\n) //=> true\r\n```\r\n\r\nAs you can see from the example above, `memoizedSelectCompletedTodos` does not run the second or third time, but we still get the same return value as last time.\r\n\r\nIn addition to skipping unnecessary recalculations, `memoizedSelectCompletedTodos` returns the existing result reference if there is no recalculation. This is important for libraries like [React-Redux] or [React] that often rely on reference equality checks to optimize UI updates.\r\n\r\n---\r\n\r\n## Terminology\r\n\r\n- <a name=\"selector-function\"></a>[**Selector Function**](#selector-function): A function that accepts one or more JavaScript values as arguments, and derives a result. When used with [Redux], the first argument is typically the entire Redux store state.\r\n- <a name=\"input-selectors\"></a>[**input selectors**](#input-selectors): Basic selector functions used as building blocks for creating a memoized selector. They are passed as the first argument(s) to [`createSelector`], and are called with all selector arguments. They are responsible for extracting and providing necessary values to the [result function].\r\n- <a name=\"output-selector\"></a>[**Output Selector**](#output-selector): The actual memoized selectors created by [`createSelector`].\r\n- <a name=\"result-function\"></a>[**Result Function**](#result-function): The function that comes after the [input selectors]. It takes the [input selectors]' return values as arguments and returns a result.\r\n- <a name=\"dependencies\"></a>[**`Dependencies`**](#dependencies): Same as [input selectors]. They are what the [output selector] \"depends\" on.\r\n\r\nThe below example serves as a visual aid:\r\n\r\n```ts\r\nconst outputSelector = createSelector(\r\n  [inputSelector1, inputSelector2, inputSelector3], // synonymous with `dependencies`.\r\n  resultFunc // Result function\r\n)\r\n```\r\n\r\n---\r\n\r\n## What's New in 5.0.0?\r\n\r\nVersion 5.0.0 introduces several new features and improvements:\r\n\r\n- **Customization Enhancements**:\r\n\r\n  - Added the ability to pass an options object to [`createSelectorCreator`], allowing for customized `memoize` and `argsMemoize` functions, alongside their respective options (`memoizeOptions` and `argsMemoizeOptions`).\r\n  - The [`createSelector`] function now supports direct customization of `memoize` and `argsMemoize` within its options object.\r\n\r\n- **Memoization Functions**:\r\n\r\n  - Introduced new experimental memoization functions: `weakMapMemoize` and `unstable_autotrackMemoize`.\r\n  - Incorporated `memoize` and `argsMemoize` into the [output selector fields] for debugging purposes.\r\n\r\n- **TypeScript Support and Performance**:\r\n\r\n  - Discontinued support for TypeScript versions below 4.7, aligning with modern TypeScript features.\r\n  - Significantly improved TypeScript performance for nesting [output selectors][output selector]. The nesting limit has increased from approximately 8 to around 30 [output selectors][output selector], greatly reducing the occurrence of the infamous `Type instantiation is excessively deep and possibly infinite` error.\r\n\r\n- **Selector API Enhancements**:\r\n\r\n  - Removed the second overload of `createStructuredSelector` due to its susceptibility to runtime errors.\r\n\r\n- **Additional Functionalities**:\r\n\r\n  - Added `dependencyRecomputations` and `resetDependencyRecomputations` to the [output selector fields]. These additions provide greater control and insight over [input selectors], complementing the new `argsMemoize` API.\r\n  - Introduced `inputStabilityCheck`, a development tool that runs the [input selectors] twice using the same arguments and triggers a warning If they return differing results for the same call.\r\n  - Introduced `identityFunctionCheck`, a development tool that checks to see if the [result function] returns its own input.\r\n\r\nThese updates aim to enhance flexibility, performance, and developer experience. For detailed usage and examples, refer to the updated documentation sections for each feature.\r\n\r\n- **Breaking Changes**:\r\n\r\n  - Removed `ParametricSelector` and `OutputParametricSelector` types. Their functionalities are now integrated into `Selector` and `OutputSelector` respectively, which inherently support additional parameters.\r\n\r\n<div align=\"right\">[ <a href=\"installation\">↑ Back to top ↑</a> ]</div>\r\n\r\n---\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## References\r\n\r\n<details><summary><b>Click to Expand</b></summary>\r\n\r\nOriginally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).\r\n\r\n[typescript-badge]: https://img.shields.io/badge/TypeScript-v4%2E7%2B-007ACC?style=for-the-badge&logo=TypeScript&logoColor=black&labelColor=blue&color=gray\r\n[build-badge]: https://img.shields.io/github/actions/workflow/status/reduxjs/reselect/build-and-test-types.yml?branch=master&style=for-the-badge\r\n[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml\r\n[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=for-the-badge\r\n[npm]: https://www.npmjs.org/package/reselect\r\n[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=for-the-badge\r\n[coveralls]: https://coveralls.io/github/reduxjs/reselect\r\n\r\n<!-- External Links -->\r\n\r\n[Redux]: https://redux.js.org 'Redux'\r\n[React]: https://react.dev 'React'\r\n[React-Redux]: https://react-redux.js.org 'React-Redux'\r\n\r\n<!-- Internal Links -->\r\n\r\n[selector]: #selector-function 'Selector Function'\r\n[input selectors]: #input-selectors 'Input Selectors'\r\n[output selector]: #output-selector 'Output Selector'\r\n[result function]: #result-function 'Result Function'\r\n[output selector fields]: https://reselect.js.org/api/createSelector#output-selector-fields 'Output Selector Fields'\r\n[`createSelector`]: https://reselect.js.org/api/createSelector 'createSelector'\r\n[`createSelectorCreator`]: https://reselect.js.org/api/createSelectorCreator 'createSelectorCreator'\r\n[`lruMemoize`]: https://reselect.js.org/api/lruMemoize 'lruMemoize'\r\n[`weakMapMemoize`]: https://reselect.js.org/api/weakMapMemoize 'weakMapMemoize'\r\n[`createStructuredSelector`]: https://reselect.js.org/api/createStructuredSelector 'createStructuredSelector'\r\n\r\n</details>\r\n","readmeFilename":"README.md","users":{"jk6":true,"vasz":true,"xhou":true,"kvrao":true,"r3nya":true,"nauhil":true,"rexpan":true,"rossjs":true,"zwwggg":true,"adrtho4":true,"edcolco":true,"ikhsaan":true,"kaashin":true,"kkho595":true,"pixel67":true,"ungurys":true,"wenbing":true,"esundahl":true,"hummatli":true,"johniexu":true,"rmanalan":true,"zhaoming":true,"abuelwafa":true,"edwardxyt":true,"justjavac":true,"ldq-first":true,"petershev":true,"qqcome110":true,"sternelee":true,"tomgao365":true,"whathejoe":true,"cfleschhut":true,"filipdanic":true,"monolithed":true,"oleg_tsyba":true,"raycharles":true,"cbetancourt":true,"coolhanddev":true,"kodekracker":true,"nisimjoseph":true,"scottcorgan":true,"dpjayasekara":true,"hugojosefson":true,"orenschwartz":true,"taylorpzreal":true,"treble.snake":true,"lassevolkmann":true,"marcelohmdias":true,"serge-nikitin":true,"derrickbeining":true,"joaquin.briceno":true,"miles_christian":true,"nbcuniversalpaint":true,"omkar.sheral.1989":true,"scott.m.sarsfield":true,"nguyenvanhoang26041994":true},"contributors":[{"name":"Lee Bannard","email":"l_bannard@yahoo.co.uk","url":"https://github.com/ellbee"},{"name":"Martijn Faassen","url":"https://github.com/faassen"},{"name":"Ian Ker-Seymer","email":"i.kerseymer@gmail.com","url":"https://github.com/ianks"},{"name":"Mike S","url":"https://github.com/SpainTrain"},{"name":"Daniel Bugl","email":"me@omnidan.net","url":"https://github.com/omnidan"},{"name":"Ryan","url":"https://github.com/ryanatkn"},{"name":"Alex Guerra","email":"alex@heyimalex.com","url":"https://github.com/HeyImAlex"},{"name":"speedskater","url":"https://github.com/speedskater"},{"name":"Daniela Borges","url":"https://github.com/sericaia"},{"name":"Brian Ng","email":"bng412@gmail.com","url":"https://github.com/existentialism"},{"name":"C. T. Lin","email":"chentsulin@gmail.com","url":"https://github.com/chentsulin"},{"name":"Jay","email":"wuceh14678@gmail.com","url":"https://github.com/chungchiehlun"},{"name":"Christian Schuhmann","url":"https://github.com/madebyherzblut"},{"name":"Daniel Barreto","email":"daniel.barreto.n@gmail.com","url":"https://github.com/volrath"},{"name":"Adam Royle","url":"https://github.com/ifunk"},{"name":"Elliot Crosby-McCullough","email":"elliot.cm@gmail.com","url":"https://github.com/elliotcm"},{"name":"frankwallis","url":"https://github.com/frankwallis"},{"name":"Jason Huang","email":"chaoju.huang@gmail.com","url":"https://github.com/kaddopur"},{"name":"Josh Kelley","url":"https://github.com/joshkel"},{"name":"Leon Aves","url":"https://github.com/leonaves"},{"name":"Mark Dalgleish","url":"https://github.com/markdalgleish"},{"name":"Max Goodman","email":"c@chromako.de","url":"https://github.com/chromakode"},{"name":"Michael Lancaster","email":"michaell.llancaster@gmail.com","url":"https://github.com/weblancaster"},{"name":"Mihail Diordiev","url":"https://github.com/zalmoxisus"},{"name":"PSpSynedra","url":"https://github.com/PSpSynedra"},{"name":"Simen Bekkhus","email":"sbekkhus91@gmail.com","url":"https://github.com/SimenB"},{"name":"Wade Peterson","url":"https://github.com/WadePeterson"},{"name":"长天之云","email":"ambar.lee@gmail.com","url":"https://github.com/ambar"},{"name":"Courtland Allen","email":"csallen@alum.mit.edu","url":"https://github.com/courthead"},{"name":"Henrik Joreteg","email":"henrik@joreteg.com","url":"https://github.com/HenrikJoreteg"},{"name":"Kyle Davis","url":"https://github.com/kyldvs"},{"name":"Salvador Hernandez","email":"s.hernandez5400@gmail.com","url":"https://github.com/clickclickonsal"},{"name":"Nick Ball","url":"https://github.com/npbee"},{"name":"mctep","url":"https://github.com/mctep"},{"name":"Jacob Rask","email":"jacob@jacobrask.net","url":"https://github.com/jacobrask"},{"name":"Luqmaan Dawoodjee","email":"ldawoodjee@gmail.com","url":"https://github.com/luqmaan"},{"name":"Walter Breakell","url":"https://github.com/wbreakell"},{"name":"Matthew Hetherington","url":"https://github.com/matthetherington"},{"name":"Mike Wilcox","email":"mwilcox56@gmail.com","url":"https://github.com/mjw56"},{"name":"David Edmondson","url":"https://github.com/threehams"},{"name":"Andrey Zaytsev","email":"za@zalab.net","url":"https://github.com/zandroid"},{"name":"1ven","url":"https://github.com/1ven"},{"name":"Alexey Yurchenko","email":"alexes.dev@gmail.com","url":"https://github.com/alexesdev"},{"name":"Douglas Russell","url":"https://github.com/dpwrussell"},{"name":"Yonatan Kogan","url":"https://github.com/yoni-tock"},{"name":"Peter Petrov","url":"https://github.com/pesho"},{"name":"Walter Breakell","url":"https://github.com/wbreakell"},{"name":"Whien","email":"sal95610@gmail.com","url":"https://github.com/madeinfree"},{"name":"Sergei Egorov","email":"bsideup@gmail.com","url":"https://github.com/bsideup"},{"name":"Jim Bolla","url":"https://github.com/jimbolla"},{"name":"Carl Bernardo","url":"https://github.com/carlbernrdo"},{"name":"Daniel Lytkin","email":"dan.lytkin@gmail.com","url":"https://github.com/aikoven"},{"name":"John Haley","email":"john@haley.io","url":"https://github.com/johnhaley81"},{"name":"Alexandre","email":"alexr.3165@gmail.com","url":"https://github.com/alex3165"}]}