diff --git a/.eslintrc b/.eslintrc index 3f6d01cb9..cd470ca15 100644 --- a/.eslintrc +++ b/.eslintrc @@ -59,7 +59,7 @@ } }, { - "files": ["**/test/**/*.ts", "**/typescript_test/**/*.ts"], + "files": ["**/test/**/*.ts", "**/type-test/**/*.ts"], "rules": { "consistent-return": "off", "max-lines": "off", diff --git a/.github/workflows/build-and-test-types.yml b/.github/workflows/build-and-test-types.yml index 392338d23..c7f96bfb2 100644 --- a/.github/workflows/build-and-test-types.yml +++ b/.github/workflows/build-and-test-types.yml @@ -1,6 +1,6 @@ name: CI -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] jobs: build: @@ -65,13 +65,15 @@ jobs: node-version: ${{ matrix.node }} cache: 'yarn' + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: package + path: . + - name: Install deps run: yarn install - # Build with the actual TS version in the repo - - name: Pack - run: yarn build && yarn pack - - name: Install build artifact run: yarn add ./package.tgz @@ -79,17 +81,17 @@ jobs: - name: Install TypeScript ${{ matrix.ts }} run: yarn add --dev typescript@${{ matrix.ts }} - - name: 'Remove source to ensure packaged types are used' - run: rm -rf src - # Remove config line that points "reselect" to the `src` folder, # so that the typetest will use the installed version instead - - run: sed -i -e /@remap-prod-remove-line/d ./typescript_test/tsconfig.json vitest.config.mts + - name: Erase path aliases + run: sed -i -e /@remap-prod-remove-line/d tsconfig.base.json - name: Test types + env: + TEST_DIST: true run: | - ./node_modules/.bin/tsc --version - yarn test:typescript + yarn tsc --version + yarn type-tests are-the-types-wrong: name: Check package config with are-the-types-wrong @@ -110,7 +112,8 @@ jobs: node-version: ${{ matrix.node }} cache: 'yarn' - - uses: actions/download-artifact@v4 + - name: Download build artifact + uses: actions/download-artifact@v4 with: name: package path: . @@ -152,6 +155,12 @@ jobs: - name: Clone RTK repo run: git clone https://github.com/reduxjs/redux-toolkit.git ./redux-toolkit + - name: Cache example deps + uses: actions/cache@v4 + with: + path: ./redux-toolkit/examples/publish-ci/${{ matrix.example }}/node_modules + key: test-published-artifact-${{ matrix.example }}-node_modules + - name: Check folder contents run: ls -l . @@ -181,17 +190,6 @@ jobs: working-directory: ./redux-toolkit/examples/publish-ci/${{ matrix.example }} run: yarn info reselect && yarn why reselect - - name: Set up JDK 17 for React Native build - if: matrix.example == 'react-native' - uses: actions/setup-java@v4 - with: - java-version: '17.x' - distribution: 'temurin' - - - name: Check MSW version - working-directory: ./redux-toolkit/examples/publish-ci/${{ matrix.example }} - run: yarn why msw - - name: Build example working-directory: ./redux-toolkit/examples/publish-ci/${{ matrix.example }} env: @@ -201,3 +199,45 @@ jobs: - name: Run test step working-directory: ./redux-toolkit/examples/publish-ci/${{ matrix.example }} run: yarn test + + test-dist: + name: Run local tests against build artifact + needs: [build] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node: ['20.x'] + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Use node ${{ matrix.node }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'yarn' + + - name: Install dependencies + run: yarn install + + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: package + path: . + + - name: Check folder contents + run: ls -lah + + - name: Install build artifact + run: yarn add ./package.tgz + + - name: Erase path aliases + run: sed -i -e /@remap-prod-remove-line/d tsconfig.base.json + + - name: Run local tests against the build artifact + env: + TEST_DIST: true + run: yarn test diff --git a/.gitignore b/.gitignore index 7a4a7e462..71f5638d9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,6 @@ dist es .vscode .idea -typescript_test/should_compile/index.js -typescript_test/should_not_compile/index.js -typescript_test/common.js flow_test/should_fail/flow-typed/index.js.flow flow_test/should_pass/flow-typed/index.js.flow reselect-builds/ @@ -34,3 +31,8 @@ website/.yarn/ docs/examples/**/*.js docs/examples/**/*.jsx + +tsconfig.vitest-temp.json + +.yalc +yalc.lock diff --git a/package.json b/package.json index 83e3b9cb1..5066a47ec 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ "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": "node --expose-gc $(yarn bin vitest) --run --typecheck", + "test:watch": "node --expose-gc $(yarn bin vitest) --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", + "type-check:trace": "vitest --run --typecheck.only && tsc --noEmit -p tsconfig.test.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace", + "type-tests": "tsc --noEmit -p tsconfig.test.json", "docs:start": "yarn --cwd website start", "docs:build": "yarn --cwd website build", "docs:clear": "yarn --cwd website clear", @@ -58,6 +58,7 @@ "@reduxjs/toolkit": "^2.0.1", "@testing-library/react": "^14.1.2", "@types/lodash": "^4.14.175", + "@types/node": "^22.15.2", "@types/react": "^18.2.38", "@types/react-dom": "^18.2.17", "@types/shelljs": "^0.8.11", @@ -82,10 +83,7 @@ "shelljs": "^0.8.5", "tsup": "^8.2.4", "typescript": "^5.8.2", - "vitest": "^1.6.0" - }, - "resolutions": { - "esbuild": "0.23.0" + "vitest": "^3.1.2" }, "packageManager": "yarn@4.4.1" } diff --git a/scripts/writeGitVersion.mjs b/scripts/writeGitVersion.mjs index 4a9efc9b8..7e8c33149 100644 --- a/scripts/writeGitVersion.mjs +++ b/scripts/writeGitVersion.mjs @@ -1,14 +1,10 @@ -import path from 'path' -import fs from 'fs' -import { fileURLToPath } from 'node:url' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) +import * as fs from 'node:fs' +import * as path from 'node:path' const gitRev = process.argv[2] -const packagePath = path.join(__dirname, '../package.json') -const pkg = JSON.parse(fs.readFileSync(packagePath)) +const packagePath = path.join(import.meta.dirname, '../package.json') +const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8')) pkg.version = `${pkg.version}-${gitRev}` fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2)) diff --git a/test/computationComparisons.spec.tsx b/test/computationComparisons.spec.tsx index 472080f05..c64fdbc30 100644 --- a/test/computationComparisons.spec.tsx +++ b/test/computationComparisons.spec.tsx @@ -3,7 +3,7 @@ */ import * as rtl from '@testing-library/react' -import React, { useLayoutEffect, useMemo } from 'react' +import { memo, useLayoutEffect, useMemo } from 'react' import type { TypedUseSelectorHook } from 'react-redux' import { Provider, shallowEqual, useSelector } from 'react-redux' import { @@ -15,18 +15,9 @@ import { import type { OutputSelector } from 'reselect' import type { RootState, Todo } from './testUtils' -import { addTodo, setupStore, toggleCompleted } from './testUtils' +import { setupStore, toggleCompleted } from './testUtils' describe('Computations and re-rendering with React components', () => { - const selector = createSelector( - (a: number) => a, - a => a - ) - - test('passes', () => { - console.log(selector(1)) - }) - let store: ReturnType beforeEach(() => { @@ -37,37 +28,40 @@ describe('Computations and re-rendering with React components', () => { }) type SelectTodoIds = OutputSelector< - [(state: RootState) => RootState['todos']], + [(state: RootState) => Todo[]], number[], typeof lruMemoize | typeof weakMapMemoize, typeof lruMemoize | typeof weakMapMemoize > type SelectTodoById = OutputSelector< - [ - (state: RootState) => RootState['todos'], - (state: RootState, id: number) => number - ], + [(state: RootState) => Todo[], (state: RootState, id: number) => number], readonly [todo: Todo | undefined], typeof lruMemoize | typeof weakMapMemoize, typeof lruMemoize | typeof weakMapMemoize > const selectTodos = (state: RootState) => state.todos - const mapTodoIds = (todos: RootState['todos']) => todos.map(({ id }) => id) - const selectTodoId = (todos: RootState, id: number) => id - const mapTodoById = (todos: RootState['todos'], id: number) => { + const mapTodoIds = (todos: Todo[]) => todos.map(({ id }) => id) + const selectTodoId = (state: RootState, id: number) => id + const mapTodoById = (todos: Todo[], id: number) => { // Intentionally return this wrapped in an array to force a new reference each time return [todos.find(todo => todo.id === id)] as const } - const selectTodoIdsDefault = createSelector([selectTodos], mapTodoIds) - console.log(`selectTodoIdsDefault name: ${selectTodoIdsDefault.name}`) + const selectTodoIdsLru = createSelector([selectTodos], mapTodoIds, { + argsMemoize: lruMemoize, + memoize: lruMemoize + }) - const selectTodoIdsResultEquality = createSelector( + const selectTodoIdsLruResultEquality = createSelector( [selectTodos], mapTodoIds, - { memoizeOptions: { resultEqualityCheck: shallowEqual } } + { + memoizeOptions: { resultEqualityCheck: shallowEqual }, + memoize: lruMemoize, + argsMemoize: lruMemoize + } ) const selectTodoIdsWeakMap = createSelector([selectTodos], mapTodoIds, { @@ -85,16 +79,18 @@ describe('Computations and re-rendering with React components', () => { } ) - const selectTodoByIdDefault = createSelector( + const selectTodoByIdLru = createSelector( [selectTodos, selectTodoId], - mapTodoById + mapTodoById, + { memoize: lruMemoize, argsMemoize: lruMemoize } ) - const selectTodoByIdResultEquality = createSelector( + const selectTodoByIdLruResultEquality = createSelector( [selectTodos, selectTodoId], mapTodoById, { memoize: lruMemoize, + argsMemoize: lruMemoize, memoizeOptions: { resultEqualityCheck: shallowEqual, maxSize: 500 } } ) @@ -111,7 +107,7 @@ describe('Computations and re-rendering with React components', () => { let listRenders = 0 let listItemMounts = 0 - const TodoListItem = React.memo(function TodoListItem({ + const TodoListItem = memo(function TodoListItem({ id, selectTodoById }: { @@ -160,11 +156,11 @@ describe('Computations and re-rendering with React components', () => { } const testCases: [string, SelectTodoIds, SelectTodoById][] = [ - ['default', selectTodoIdsDefault, selectTodoByIdDefault], + ['lru', selectTodoIdsLru, selectTodoByIdLru], [ - 'resultEquality', - selectTodoIdsResultEquality, - selectTodoByIdResultEquality + 'lruResultEquality', + selectTodoIdsLruResultEquality, + selectTodoByIdLruResultEquality ], ['weakMap', selectTodoIdsWeakMap, selectTodoByIdWeakMap], @@ -175,7 +171,7 @@ describe('Computations and re-rendering with React components', () => { ] ] - test.each(testCases)(`%s`, async (name, selectTodoIds, selectTodoById) => { + test.each(testCases)(`%s`, (name, selectTodoIds, selectTodoById) => { selectTodoIds.resetRecomputations() selectTodoIds.resetDependencyRecomputations() selectTodoById.resetRecomputations() @@ -193,51 +189,7 @@ describe('Computations and re-rendering with React components', () => { ) - // console.log(`Recomputations after render (${name}): `) - // console.log('selectTodoIds: ') - // logSelectorRecomputations(selectTodoIds as any) - // console.log('selectTodoById: ') - // logSelectorRecomputations(selectTodoById as any) - - // console.log('Render count: ', { - // listRenders, - // listItemRenders, - // listItemMounts - // }) - expect(listItemRenders).toBe(numTodos) - - rtl.act(() => { - store.dispatch(toggleCompleted(3)) - }) - - // console.log(`\nRecomputations after toggle completed (${name}): `) - // console.log('selectTodoIds: ') - // logSelectorRecomputations(selectTodoIds as any) - // console.log('selectTodoById: ') - // logSelectorRecomputations(selectTodoById as any) - - // console.log('Render count: ', { - // listRenders, - // listItemRenders, - // listItemMounts - // }) - - rtl.act(() => { - store.dispatch(addTodo({ title: 'a', description: 'b' })) - }) - - // console.log(`\nRecomputations after added (${name}): `) - // console.log('selectTodoIds: ') - // // logSelectorRecomputations(selectTodoIds as any) - // console.log('selectTodoById: ') - // // logSelectorRecomputations(selectTodoById as any) - - // console.log('Render count: ', { - // listRenders, - // listItemRenders, - // listItemMounts - // }) }) }) diff --git a/test/examples.test.ts b/test/examples.test.ts index 52132c941..b78cc5e59 100644 --- a/test/examples.test.ts +++ b/test/examples.test.ts @@ -1,3 +1,4 @@ +import type { AnyFunction } from '@internal/types' import type { OutputSelector, Selector, @@ -39,7 +40,7 @@ test('empty array', () => { }) test('identity', () => { - const identity = any>(func: Func) => func + const identity = (func: Func) => func const createNonMemoizedSelector = createSelectorCreator({ memoize: identity, argsMemoize: identity diff --git a/test/identityFunctionCheck.test.ts b/test/identityFunctionCheck.test.ts index fa7fd225e..6a776cb80 100644 --- a/test/identityFunctionCheck.test.ts +++ b/test/identityFunctionCheck.test.ts @@ -1,5 +1,5 @@ import { createSelector, setGlobalDevModeChecks } from 'reselect' -import type { LocalTestContext, RootState } from './testUtils' +import type { RootState } from './testUtils' import { localTest } from './testUtils' describe('identityFunctionCheck', () => { diff --git a/test/lruMemoize.test.ts b/test/lruMemoize.test.ts index 6c42808eb..161f3a5a4 100644 --- a/test/lruMemoize.test.ts +++ b/test/lruMemoize.test.ts @@ -435,6 +435,7 @@ describe(lruMemoize, () => { [(state, id: number) => state[id]], state => state, { + devModeChecks: { identityFunctionCheck: 'never' }, argsMemoizeOptions: { maxSize: 10 }, memoizeOptions: { maxSize: 10 } } diff --git a/test/perfComparisons.spec.ts b/test/perfComparisons.spec.ts index 506703977..6704cfc40 100644 --- a/test/perfComparisons.spec.ts +++ b/test/perfComparisons.spec.ts @@ -252,7 +252,7 @@ describe('More perf comparisons', () => { // }) }) - it.skip('weakMapMemoizer recalcs', () => { + it.skip('weakMapMemoize recalculations', () => { const state1 = store.getState() store.dispatch(counterSlice.actions.increment1()) diff --git a/test/reselect.spec.ts b/test/reselect.spec.ts index a11767a41..4a8bf2a33 100644 --- a/test/reselect.spec.ts +++ b/test/reselect.spec.ts @@ -299,11 +299,11 @@ describe('Combining selectors', () => { test('override valueEquals', () => { // a rather absurd equals operation we can verify in tests - const createOverridenSelector = createSelectorCreator( + const createOverriddenSelector = createSelectorCreator( lruMemoize, (a, b) => typeof a === typeof b ) - const selector = createOverridenSelector( + const selector = createOverriddenSelector( (state: StateA) => state.a, a => a, { devModeChecks: { identityFunctionCheck: 'never' } } diff --git a/test/selectorUtils.spec.ts b/test/selectorUtils.spec.ts index 47b3508dd..39c703912 100644 --- a/test/selectorUtils.spec.ts +++ b/test/selectorUtils.spec.ts @@ -1,5 +1,5 @@ import { createSelector, lruMemoize } from 'reselect' -import type { StateA, StateAB } from 'testTypes' +import type { StateA, StateAB } from './testTypes' describe('createSelector exposed utils', () => { test('resetRecomputations', () => { diff --git a/test/setup.vitest.ts b/test/setup.ts similarity index 100% rename from test/setup.vitest.ts rename to test/setup.ts diff --git a/test/testUtils.ts b/test/testUtils.ts index aa1e69454..626424413 100644 --- a/test/testUtils.ts +++ b/test/testUtils.ts @@ -1,7 +1,8 @@ +import type { AnyFunction, Simplify } from '@internal/types' import type { PayloadAction } from '@reduxjs/toolkit' import { combineReducers, configureStore, createSlice } from '@reduxjs/toolkit' import { test } from 'vitest' -import type { AnyFunction, OutputSelector, Simplify } from '../src/types' +import type { OutputSelector } from 'reselect' export interface Todo { id: number diff --git a/test/tsconfig.json b/test/tsconfig.json deleted file mode 100644 index 0d98c80c8..000000000 --- a/test/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "module": "ESNext", - "moduleResolution": "Node", - "emitDeclarationOnly": false, - "strict": true, - "noEmit": true, - "target": "ESNext", - "jsx": "react", - "baseUrl": ".", - "rootDir": "../", - "skipLibCheck": true, - "noImplicitReturns": false, - "noUnusedLocals": false, - "types": ["vitest/globals"], - "paths": { - "reselect": ["../src/index.ts"], // @remap-prod-remove-line - "@internal/*": ["../src/*"] - } - }, - "include": ["**/*.ts*"] -} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 000000000..88ecaa6e3 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "declaration": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["DOM", "ESNext"], + "module": "ESNext", + "moduleResolution": "Node", + "noErrorTruncation": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "paths": { + "@internal/*": ["./src/*"], + "reselect": ["./src/index.ts"] // @remap-prod-remove-line + }, + "resolveJsonModule": true, + "rootDir": "./src", + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "target": "ESNext", + "types": ["vitest/globals", "vitest/importMeta"], + "useDefineForClassFields": true, + "useUnknownInCatchVariables": true + }, + "exclude": ["dist", "website", "docs"] +} diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 000000000..c38223c25 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,11 @@ +{ + // For building the library. + "extends": "./tsconfig.base.json", + "compilerOptions": { + "emitDeclarationOnly": true, + "jsx": "react", + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json index 2e6934359..e49b10523 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,28 +1,11 @@ { + // For general development and intellisense. + // Scans the entire source code against the current TS version + // we are using during development. + "extends": "./tsconfig.test.json", "compilerOptions": { - "strict": true, - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Node", - "esModuleInterop": true, - "skipLibCheck": true, "allowJs": true, - "jsx": "react", - "noErrorTruncation": true, - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "dist", - "forceConsistentCasingInFileNames": true, - "experimentalDecorators": true, - "rootDirs": ["./src"], - "rootDir": ".", - "types": ["vitest/globals", "vitest/importMeta"], - "baseUrl": ".", - "paths": { - "reselect": ["src/index.ts"], // @remap-prod-remove-line - "@internal/*": ["src/*"] - } + "checkJs": true }, - "include": ["./src/**/*"], - "exclude": ["node_modules", "dist"] + "include": ["."] } diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 000000000..0995aae05 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,9 @@ +{ + // For type tests during CI. + "extends": "./tsconfig.base.json", + "compilerOptions": { + "noEmit": true, + "rootDir": "./" + }, + "include": ["type-tests"] +} diff --git a/tsup.config.ts b/tsup.config.ts index 4831184ba..31f7e203b 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -15,6 +15,8 @@ if (process.env.NODE_ENV === 'production') { ) } +const tsconfig = 'tsconfig.build.json' satisfies Options['tsconfig'] + export default defineConfig((options): Options[] => { const commonOptions: Options = { entry: { @@ -22,6 +24,7 @@ export default defineConfig((options): Options[] => { }, sourcemap: true, target: ['esnext'], + tsconfig, clean: true, ...options } diff --git a/type-tests/argsMemoize.test-d.ts b/type-tests/argsMemoize.test-d.ts index d7f2c51c1..0e8412089 100644 --- a/type-tests/argsMemoize.test-d.ts +++ b/type-tests/argsMemoize.test-d.ts @@ -7,7 +7,7 @@ import { lruMemoize, weakMapMemoize } from 'reselect' -import { assertType, describe, expectTypeOf, test } from 'vitest' +import { describe, expectTypeOf, test } from 'vitest' interface RootState { todos: { @@ -23,38 +23,44 @@ const state: RootState = { ] } -describe('memoize and argsMemoize', () => { +describe('type tests', () => { test('Override Only Memoize In createSelector', () => { const selectorDefaultSeparateInlineArgs = createSelector( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: lruMemoize } ) + const selectorDefaultArgsAsArray = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { memoize: lruMemoize } ) + const selectorDefaultArgsAsArrayWithMemoizeOptions = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { memoize: lruMemoize, memoizeOptions: { maxSize: 2 } } ) + const selectorDefaultSeparateInlineArgsWithMemoizeOptions = createSelector( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: lruMemoize, memoizeOptions: { maxSize: 2 } } ) + const selectorAutotrackSeparateInlineArgs = createSelector( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: autotrackMemoize } ) + const selectorAutotrackArgsAsArray = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { memoize: autotrackMemoize } ) + // @ts-expect-error When memoize is autotrackMemoize, type of memoizeOptions needs to be the same as options args in autotrackMemoize. const selectorAutotrackArgsAsArrayWithMemoizeOptions = createSelector( [(state: RootState) => state.todos], @@ -62,6 +68,7 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { memoize: autotrackMemoize, memoizeOptions: { maxSize: 2 } } ) + const selectorAutotrackSeparateInlineArgsWithMemoizeOptions = // @ts-expect-error When memoize is autotrackMemoize, type of memoizeOptions needs to be the same as options args in autotrackMemoize. createSelector( @@ -70,16 +77,19 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { memoize: autotrackMemoize, memoizeOptions: { maxSize: 2 } } ) + const selectorWeakMapSeparateInlineArgs = createSelector( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: weakMapMemoize } ) + const selectorWeakMapArgsAsArray = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { memoize: weakMapMemoize } ) + // @ts-expect-error When memoize is weakMapMemoize, type of memoizeOptions needs to be the same as options args in weakMapMemoize. const selectorWeakMapArgsAsArrayWithMemoizeOptions = createSelector( [(state: RootState) => state.todos], @@ -87,6 +97,7 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { memoize: weakMapMemoize, memoizeOptions: { maxSize: 2 } } ) + // @ts-expect-error When memoize is weakMapMemoize, type of memoizeOptions needs to be the same as options args in weakMapMemoize. const selectorWeakMapSeparateInlineArgsWithMemoizeOptions = createSelector( (state: RootState) => state.todos, @@ -94,24 +105,31 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { memoize: weakMapMemoize, memoizeOptions: { maxSize: 2 } } ) + const createSelectorDefault = createSelectorCreator(lruMemoize) + const createSelectorWeakMap = createSelectorCreator(weakMapMemoize) + const createSelectorAutotrack = createSelectorCreator(autotrackMemoize) + const changeMemoizeMethodSelectorDefault = createSelectorDefault( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: weakMapMemoize } ) + const changeMemoizeMethodSelectorWeakMap = createSelectorWeakMap( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: lruMemoize } ) + const changeMemoizeMethodSelectorAutotrack = createSelectorAutotrack( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: lruMemoize } ) + const changeMemoizeMethodSelectorDefaultWithMemoizeOptions = // @ts-expect-error When memoize is changed to weakMapMemoize or autotrackMemoize, memoizeOptions cannot be the same type as options args in lruMemoize. createSelectorDefault( @@ -120,12 +138,14 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { memoize: weakMapMemoize, memoizeOptions: { maxSize: 2 } } ) + const changeMemoizeMethodSelectorWeakMapWithMemoizeOptions = createSelectorWeakMap( (state: RootState) => state.todos, todos => todos.map(t => t.id), { memoize: lruMemoize, memoizeOptions: { maxSize: 2 } } // When memoize is changed to lruMemoize, memoizeOptions can now be the same type as options args in lruMemoize. ) + const changeMemoizeMethodSelectorAutotrackWithMemoizeOptions = createSelectorAutotrack( (state: RootState) => state.todos, @@ -140,31 +160,37 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { argsMemoize: lruMemoize } ) + const selectorDefaultArgsAsArray = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { argsMemoize: lruMemoize } ) + const selectorDefaultArgsAsArrayWithMemoizeOptions = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { argsMemoize: lruMemoize, argsMemoizeOptions: { maxSize: 2 } } ) + const selectorDefaultSeparateInlineArgsWithMemoizeOptions = createSelector( (state: RootState) => state.todos, todos => todos.map(t => t.id), { argsMemoize: lruMemoize, argsMemoizeOptions: { maxSize: 2 } } ) + const selectorAutotrackSeparateInlineArgs = createSelector( (state: RootState) => state.todos, todos => todos.map(t => t.id), { argsMemoize: autotrackMemoize } ) + const selectorAutotrackArgsAsArray = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { argsMemoize: autotrackMemoize } ) + // @ts-expect-error When argsMemoize is autotrackMemoize, type of argsMemoizeOptions needs to be the same as options args in autotrackMemoize. const selectorAutotrackArgsAsArrayWithMemoizeOptions = createSelector( [(state: RootState) => state.todos], @@ -175,6 +201,7 @@ describe('memoize and argsMemoize', () => { argsMemoizeOptions: { maxSize: 2 } } ) + const selectorAutotrackSeparateInlineArgsWithMemoizeOptions = // @ts-expect-error When argsMemoize is autotrackMemoize, type of argsMemoizeOptions needs to be the same as options args in autotrackMemoize. createSelector( @@ -186,16 +213,19 @@ describe('memoize and argsMemoize', () => { argsMemoizeOptions: { maxSize: 2 } } ) + const selectorWeakMapSeparateInlineArgs = createSelector( (state: RootState) => state.todos, todos => todos.map(t => t.id), { argsMemoize: weakMapMemoize } ) + const selectorWeakMapArgsAsArray = createSelector( [(state: RootState) => state.todos], todos => todos.map(t => t.id), { argsMemoize: weakMapMemoize } ) + // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. const selectorWeakMapArgsAsArrayWithMemoizeOptions = createSelector( [(state: RootState) => state.todos], @@ -203,6 +233,7 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { argsMemoize: weakMapMemoize, argsMemoizeOptions: { maxSize: 2 } } ) + // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. const selectorWeakMapSeparateInlineArgsWithMemoizeOptions = createSelector( (state: RootState) => state.todos, @@ -210,6 +241,7 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { argsMemoize: weakMapMemoize, argsMemoizeOptions: { maxSize: 2 } } ) + // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. const selectorWeakMapSeparateInlineArgsWithMemoizeOptions1 = createSelector( [ @@ -222,6 +254,7 @@ describe('memoize and argsMemoize', () => { argsMemoizeOptions: { maxSize: 2 } } ) + // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. const selectorWeakMapSeparateInlineArgsWithMemoizeOptions2 = createSelector( (state: RootState) => state.todos, @@ -232,7 +265,7 @@ describe('memoize and argsMemoize', () => { argsMemoize: weakMapMemoize, memoizeOptions: { equalityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b, maxSize: 2 }, @@ -243,6 +276,7 @@ describe('memoize and argsMemoize', () => { const createSelectorLruMemoize = createSelectorCreator({ memoize: lruMemoize }) + const selectorWeakMapSeparateInlineArgsWithMemoizeOptions3 = // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. createSelectorLruMemoize( @@ -252,11 +286,10 @@ describe('memoize and argsMemoize', () => { { memoize: lruMemoize, argsMemoize: weakMapMemoize, - // memoizeOptions: [], memoizeOptions: [ { equalityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b, maxSize: 2 } @@ -264,6 +297,7 @@ describe('memoize and argsMemoize', () => { argsMemoizeOptions: [{ maxSize: 2 }] } ) + const selectorWeakMapSeparateInlineArgsWithMemoizeOptions4 = createSelectorLruMemoize( // @ts-expect-error @@ -273,10 +307,11 @@ describe('memoize and argsMemoize', () => { { memoizeOptions: [{ isPromise: false }], argsMemoizeOptions: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b } ) + const selectorWeakMapSeparateInlineArgsWithMemoizeOptions5 = // @ts-expect-error createSelectorLruMemoize( @@ -287,9 +322,9 @@ describe('memoize and argsMemoize', () => { argsMemoize: weakMapMemoize, memoizeOptions: [{ isPromise: false }], argsMemoizeOptions: [] - // argsMemoizeOptions: (a, b) => a === b } ) + const selectorWeakMapSeparateInlineArgsWithMemoizeOptions6 = createSelectorLruMemoize( (state: RootState) => state.todos, @@ -299,27 +334,33 @@ describe('memoize and argsMemoize', () => { memoize: weakMapMemoize, memoizeOptions: [], argsMemoizeOptions: [] - // argsMemoizeOptions: (a, b) => a === b } ) + const createSelectorDefault = createSelectorCreator(lruMemoize) + const createSelectorWeakMap = createSelectorCreator(weakMapMemoize) + const createSelectorAutotrack = createSelectorCreator(autotrackMemoize) + const changeMemoizeMethodSelectorDefault = createSelectorDefault( (state: RootState) => state.todos, todos => todos.map(t => t.id), { argsMemoize: weakMapMemoize } ) + const changeMemoizeMethodSelectorWeakMap = createSelectorWeakMap( (state: RootState) => state.todos, todos => todos.map(t => t.id), { argsMemoize: lruMemoize } ) + const changeMemoizeMethodSelectorAutotrack = createSelectorAutotrack( (state: RootState) => state.todos, todos => todos.map(t => t.id), { argsMemoize: lruMemoize } ) + const changeMemoizeMethodSelectorDefaultWithMemoizeOptions = // @ts-expect-error When argsMemoize is changed to weakMapMemoize or autotrackMemoize, argsMemoizeOptions cannot be the same type as options args in lruMemoize. createSelectorDefault( @@ -328,12 +369,14 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { argsMemoize: weakMapMemoize, argsMemoizeOptions: { maxSize: 2 } } ) + const changeMemoizeMethodSelectorWeakMapWithMemoizeOptions = createSelectorWeakMap( (state: RootState) => state.todos, todos => todos.map(t => t.id), { argsMemoize: lruMemoize, argsMemoizeOptions: { maxSize: 2 } } // When argsMemoize is changed to lruMemoize, argsMemoizeOptions can now be the same type as options args in lruMemoize. ) + const changeMemoizeMethodSelectorAutotrackWithMemoizeOptions = createSelectorAutotrack( (state: RootState) => state.todos, @@ -346,54 +389,84 @@ describe('memoize and argsMemoize', () => { const createSelectorMicroMemoize = createSelectorCreator({ memoize: microMemoize, memoizeOptions: [{ isEqual: (a, b) => a === b }], - // memoizeOptions: { isEqual: (a, b) => a === b }, argsMemoize: microMemoize, argsMemoizeOptions: { isEqual: (a, b) => a === b } }) + const selectorMicroMemoize = createSelectorMicroMemoize( (state: RootState) => state.todos, todos => todos.map(({ id }) => id) ) - assertType(selectorMicroMemoize(state)) - // @ts-expect-error - selectorMicroMemoize() + + expectTypeOf(selectorMicroMemoize(state)).items.toBeNumber() + + expectTypeOf(selectorMicroMemoize).parameter(0).not.toBeNever() + // Checking existence of fields related to `argsMemoize` - selectorMicroMemoize.cache - selectorMicroMemoize.fn() - selectorMicroMemoize.isMemoized - selectorMicroMemoize.options - // @ts-expect-error - selectorMicroMemoize.clearCache() + + expectTypeOf(selectorMicroMemoize).toHaveProperty('cache').toBeObject() + + expectTypeOf(selectorMicroMemoize).toHaveProperty('fn').toBeFunction() + + expectTypeOf(selectorMicroMemoize) + .toHaveProperty('isMemoized') + .toEqualTypeOf(true) + + expectTypeOf(selectorMicroMemoize).toHaveProperty('options').toBeObject() + + expectTypeOf(selectorMicroMemoize).not.toHaveProperty('clearCache') + // Checking existence of fields related to `memoize` - selectorMicroMemoize.memoizedResultFunc.cache - selectorMicroMemoize.memoizedResultFunc.fn() - selectorMicroMemoize.memoizedResultFunc.isMemoized - selectorMicroMemoize.memoizedResultFunc.options - // @ts-expect-error - selectorMicroMemoize.memoizedResultFunc.clearCache() + + expectTypeOf(selectorMicroMemoize.memoizedResultFunc) + .toHaveProperty('cache') + .toBeObject() + + expectTypeOf(selectorMicroMemoize.memoizedResultFunc) + .toHaveProperty('fn') + .toBeFunction() + + expectTypeOf(selectorMicroMemoize.memoizedResultFunc) + .toHaveProperty('isMemoized') + .toEqualTypeOf(true) + + expectTypeOf(selectorMicroMemoize.memoizedResultFunc) + .toHaveProperty('options') + .toBeObject() + + expectTypeOf(selectorMicroMemoize.memoizedResultFunc).not.toHaveProperty( + 'clearCache' + ) + // Checking existence of fields related to the actual memoized selector - selectorMicroMemoize.dependencies - assertType< + + expectTypeOf(selectorMicroMemoize.dependencies).toEqualTypeOf< [ (state: RootState) => { id: number completed: boolean }[] ] - >(selectorMicroMemoize.dependencies) - assertType(selectorMicroMemoize.lastResult()) - // @ts-expect-error - selectorMicroMemoize.memoizedResultFunc() - assertType( + >() + + expectTypeOf(selectorMicroMemoize.lastResult()).items.toBeNumber() + + expectTypeOf(selectorMicroMemoize.memoizedResultFunc) + .parameter(0) + .not.toBeNever() + + expectTypeOf( selectorMicroMemoize.memoizedResultFunc([{ id: 0, completed: true }]) - ) - selectorMicroMemoize.recomputations() - selectorMicroMemoize.resetRecomputations() - // @ts-expect-error - selectorMicroMemoize.resultFunc() - assertType( + ).items.toBeNumber() + + expectTypeOf(selectorMicroMemoize.recomputations).toBeCallableWith() + expectTypeOf(selectorMicroMemoize.resetRecomputations).toBeCallableWith() + + expectTypeOf(selectorMicroMemoize.resultFunc).parameter(0).not.toBeNever() + + expectTypeOf( selectorMicroMemoize.resultFunc([{ id: 0, completed: true }]) - ) + ).items.toBeNumber() // Checking to see if types dynamically change if memoize or argsMemoize are overridden inside `createSelector`. // `microMemoize` was initially passed into `createSelectorCreator` @@ -411,52 +484,94 @@ describe('memoize and argsMemoize', () => { argsMemoizeOptions: { equalityCheck: (a, b) => a === b, maxSize: 3 } } ) - assertType(selectorMicroMemoizeOverridden(state)) - // @ts-expect-error - selectorMicroMemoizeOverridden() + + expectTypeOf(selectorMicroMemoizeOverridden(state)).items.toBeNumber() + + expectTypeOf(selectorMicroMemoizeOverridden).parameter(0).not.toBeNever() + // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverridden.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.options + + // Prior to override, this field did NOT exist. + expectTypeOf(selectorMicroMemoizeOverridden) + .toHaveProperty('clearCache') + .toBeFunction() + + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverridden).not.toHaveProperty('cache') + + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverridden).not.toHaveProperty('fn') + + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverridden).not.toHaveProperty( + 'isMemoized' + ) + + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverridden).not.toHaveProperty('options') + // Checking existence of fields related to `memoize` - selectorMicroMemoizeOverridden.memoizedResultFunc.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.options + + // Prior to override, this field did NOT exist. + expectTypeOf(selectorMicroMemoizeOverridden.memoizedResultFunc) + .toHaveProperty('clearCache') + .toBeFunction() + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverridden.memoizedResultFunc + ).not.toHaveProperty('cache') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverridden.memoizedResultFunc + ).not.toHaveProperty('fn') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverridden.memoizedResultFunc + ).not.toHaveProperty('isMemoized') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverridden.memoizedResultFunc + ).not.toHaveProperty('options') + // Checking existence of fields related to the actual memoized selector - assertType< + + expectTypeOf(selectorMicroMemoizeOverridden.dependencies).toEqualTypeOf< [ (state: RootState) => { id: number completed: boolean }[] ] - >(selectorMicroMemoizeOverridden.dependencies) - assertType( + >() + + expectTypeOf( selectorMicroMemoizeOverridden.memoizedResultFunc([ { id: 0, completed: true } ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverridden.memoizedResultFunc() - selectorMicroMemoizeOverridden.recomputations() - selectorMicroMemoizeOverridden.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverridden.resultFunc() - assertType( + ).items.toBeNumber() + + expectTypeOf( + selectorMicroMemoizeOverridden.memoizedResultFunc + ).not.toBeNever() + + expectTypeOf( + selectorMicroMemoizeOverridden.recomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeOverridden.resetRecomputations + ).toBeCallableWith() + + expectTypeOf(selectorMicroMemoizeOverridden.resultFunc).not.toBeNever() + + expectTypeOf( selectorMicroMemoizeOverridden.resultFunc([{ id: 0, completed: true }]) - ) + ).items.toBeNumber() + // Making sure the type behavior is consistent when args are passed in as an array. const selectorMicroMemoizeOverriddenArray = createSelectorMicroMemoize( [(state: RootState) => state.todos], @@ -468,54 +583,107 @@ describe('memoize and argsMemoize', () => { argsMemoizeOptions: { equalityCheck: (a, b) => a === b, maxSize: 3 } } ) - assertType(selectorMicroMemoizeOverriddenArray(state)) - // @ts-expect-error - selectorMicroMemoizeOverriddenArray() + + expectTypeOf(selectorMicroMemoizeOverriddenArray(state)).items.toBeNumber() + + expectTypeOf(selectorMicroMemoizeOverriddenArray) + .parameter(0) + .not.toBeNever() + // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverriddenArray.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.options + + // Prior to override, this field did NOT exist. + expectTypeOf(selectorMicroMemoizeOverriddenArray) + .toHaveProperty('clearCache') + .toBeFunction() + + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverriddenArray).not.toHaveProperty( + 'cache' + ) + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverriddenArray).not.toHaveProperty('fn') + + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverriddenArray).not.toHaveProperty( + 'isMemoized' + ) + + // Prior to override, this field DID exist. + expectTypeOf(selectorMicroMemoizeOverriddenArray).not.toHaveProperty( + 'options' + ) + // Checking existence of fields related to `memoize` - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.options + + // Prior to override, this field did NOT exist. + expectTypeOf(selectorMicroMemoizeOverriddenArray.memoizedResultFunc) + .toHaveProperty('clearCache') + .toBeFunction() + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverriddenArray.memoizedResultFunc + ).not.toHaveProperty('cache') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverriddenArray.memoizedResultFunc + ).not.toHaveProperty('fn') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverriddenArray.memoizedResultFunc + ).not.toHaveProperty('isMemoized') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverriddenArray.memoizedResultFunc + ).not.toHaveProperty('options') + // Checking existence of fields related to the actual memoized selector - assertType< + + expectTypeOf( + selectorMicroMemoizeOverriddenArray.dependencies + ).toEqualTypeOf< [ (state: RootState) => { id: number completed: boolean }[] ] - >(selectorMicroMemoizeOverriddenArray.dependencies) - assertType( + >() + + expectTypeOf( + selectorMicroMemoizeOverriddenArray.lastResult() + ).items.toBeNumber() + + expectTypeOf( selectorMicroMemoizeOverriddenArray.memoizedResultFunc([ { id: 0, completed: true } ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverriddenArray.memoizedResultFunc() - selectorMicroMemoizeOverriddenArray.recomputations() - selectorMicroMemoizeOverriddenArray.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverriddenArray.resultFunc() - assertType( + ).items.toBeNumber() + + expectTypeOf( + selectorMicroMemoizeOverriddenArray.memoizedResultFunc + ).not.toBeNever() + + expectTypeOf( + selectorMicroMemoizeOverriddenArray.recomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeOverriddenArray.resetRecomputations + ).toBeCallableWith() + + expectTypeOf(selectorMicroMemoizeOverriddenArray.resultFunc).not.toBeNever() + + expectTypeOf( selectorMicroMemoizeOverriddenArray.resultFunc([ { id: 0, completed: true } ]) - ) + ).items.toBeNumber() + const selectorMicroMemoizeOverrideArgsMemoizeOnlyWrong = // @ts-expect-error Because `memoizeOptions` should not contain `resultEqualityCheck`. createSelectorMicroMemoize( @@ -526,7 +694,7 @@ describe('memoize and argsMemoize', () => { memoizeOptions: { isPromise: false, resultEqualityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b }, argsMemoizeOptions: { resultEqualityCheck: (a, b) => a === b } @@ -542,56 +710,110 @@ describe('memoize and argsMemoize', () => { argsMemoizeOptions: { resultEqualityCheck: (a, b) => a === b } } ) - assertType(selectorMicroMemoizeOverrideArgsMemoizeOnly(state)) - // @ts-expect-error - selectorMicroMemoizeOverrideArgsMemoizeOnly() + + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly(state) + ).items.toBeNumber() + + expectTypeOf(selectorMicroMemoizeOverrideArgsMemoizeOnly) + .parameter(0) + .not.toBeNever() + // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverrideArgsMemoizeOnly.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.options + + // Prior to override, this field did NOT exist. + expectTypeOf(selectorMicroMemoizeOverrideArgsMemoizeOnly) + .toHaveProperty('clearCache') + .toBeFunction() + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly + ).not.toHaveProperty('cache') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly + ).not.toHaveProperty('fn') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly + ).not.toHaveProperty('isMemoized') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly + ).not.toHaveProperty('options') // Checking existence of fields related to `memoize`, these should still be the same. - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.cache - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.fn() - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.isMemoized - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.options - // @ts-expect-error Note that since we did not override `memoize` in the options object, + + expectTypeOf(selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc) + .toHaveProperty('cache') + .toBeObject() + + expectTypeOf(selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc) + .toHaveProperty('fn') + .toBeFunction() + + expectTypeOf(selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc) + .toHaveProperty('isMemoized') + .toEqualTypeOf(true) + + expectTypeOf(selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc) + .toHaveProperty('options') + .toBeObject() + + // Note that since we did not override `memoize` in the options object, // `memoizedResultFunc.clearCache` is still an invalid field access. - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.clearCache() + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc + ).not.toHaveProperty('clearCache') + // Checking existence of fields related to the actual memoized selector - assertType< + + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly.dependencies + ).toEqualTypeOf< [ (state: RootState) => { id: number completed: boolean }[] ] - >(selectorMicroMemoizeOverrideArgsMemoizeOnly.dependencies) - assertType( + >() + + expectTypeOf( selectorMicroMemoizeOverrideArgsMemoizeOnly.lastResult() - ) - assertType( + ).items.toBeNumber() + + expectTypeOf( selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc([ { id: 0, completed: true } ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc() - selectorMicroMemoizeOverrideArgsMemoizeOnly.recomputations() - selectorMicroMemoizeOverrideArgsMemoizeOnly.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverrideArgsMemoizeOnly.resultFunc() - assertType( + ).items.toBeNumber() + + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc + ).not.toBeNever() + + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly.recomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly.resetRecomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeOverrideArgsMemoizeOnly.resultFunc + ).not.toBeNever() + + expectTypeOf( selectorMicroMemoizeOverrideArgsMemoizeOnly.resultFunc([ { id: 0, completed: true } ]) - ) + ).items.toBeNumber() const selectorMicroMemoizeOverrideMemoizeOnly = createSelectorMicroMemoize( (state: RootState) => state.todos, @@ -601,56 +823,110 @@ describe('memoize and argsMemoize', () => { memoizeOptions: { resultEqualityCheck: (a, b) => a === b } } ) - assertType(selectorMicroMemoizeOverrideMemoizeOnly(state)) - // @ts-expect-error - selectorMicroMemoizeOverrideMemoizeOnly() + + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly(state) + ).items.toBeNumber() + + expectTypeOf(selectorMicroMemoizeOverrideMemoizeOnly) + .parameter(0) + .not.toBeNever() // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverrideMemoizeOnly.cache - selectorMicroMemoizeOverrideMemoizeOnly.fn - selectorMicroMemoizeOverrideMemoizeOnly.isMemoized - selectorMicroMemoizeOverrideMemoizeOnly.options - // @ts-expect-error Note that since we did not override `argsMemoize` in the options object, + + expectTypeOf(selectorMicroMemoizeOverrideMemoizeOnly) + .toHaveProperty('cache') + .toBeObject() + + expectTypeOf(selectorMicroMemoizeOverrideMemoizeOnly) + .toHaveProperty('fn') + .toBeFunction() + + expectTypeOf(selectorMicroMemoizeOverrideMemoizeOnly) + .toHaveProperty('isMemoized') + .toEqualTypeOf(true) + + expectTypeOf(selectorMicroMemoizeOverrideMemoizeOnly) + .toHaveProperty('options') + .toBeObject() + + // Note that since we did not override `argsMemoize` in the options object, // `selector.clearCache` is still an invalid field access. - selectorMicroMemoizeOverrideMemoizeOnly.clearCache() + expectTypeOf(selectorMicroMemoizeOverrideMemoizeOnly).not.toHaveProperty( + 'clearCache' + ) // Checking existence of fields related to `memoize` - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.options - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.clearCache() // Prior to override, this field did NOT exist. + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc + ).not.toHaveProperty('cache') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc + ).not.toHaveProperty('fn') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc + ).not.toHaveProperty('isMemoized') + + // Prior to override, this field DID exist. + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc + ).not.toHaveProperty('options') + + // Prior to override, this field did NOT exist. + expectTypeOf(selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc) + .toHaveProperty('clearCache') + .toBeFunction() // Checking existence of fields related to the actual memoized selector - assertType< + + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.dependencies + ).toEqualTypeOf< [ (state: RootState) => { id: number completed: boolean }[] ] - >(selectorMicroMemoizeOverrideMemoizeOnly.dependencies) - assertType(selectorMicroMemoizeOverrideMemoizeOnly.lastResult()) - assertType( + >() + + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.lastResult() + ).items.toBeNumber() + + expectTypeOf( selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc([ { id: 0, completed: true } ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc() - selectorMicroMemoizeOverrideMemoizeOnly.recomputations() - selectorMicroMemoizeOverrideMemoizeOnly.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverrideMemoizeOnly.resultFunc() - assertType( + ).items.toBeNumber() + + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc + ).not.toBeNever() + + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.recomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.resetRecomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeOverrideMemoizeOnly.resultFunc + ).not.toBeNever() + + expectTypeOf( selectorMicroMemoizeOverrideMemoizeOnly.resultFunc([ { id: 0, completed: true } ]) - ) + ).items.toBeNumber() const selectorMicroMemoizePartiallyOverridden = // @ts-expect-error Since `argsMemoize` is set to `lruMemoize`, `argsMemoizeOptions` must match the options object parameter of `lruMemoize` @@ -663,7 +939,7 @@ describe('memoize and argsMemoize', () => { argsMemoize: lruMemoize, memoizeOptions: { equalityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b, maxSize: 2 }, @@ -682,7 +958,7 @@ describe('memoize and argsMemoize', () => { memoizeOptions: [ { equalityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b, maxSize: 2 } @@ -693,17 +969,7 @@ describe('memoize and argsMemoize', () => { const selectorMicroMemoizePartiallyOverridden2 = createSelectorMicroMemoize( (state: RootState) => state.todos, todos => todos.map(t => t.id), - { - // memoizeOptions: [ - // { - // equalityCheck: - // // @ts-expect-error - // (a, b) => a === b, - // maxSize: 2 - // } - // ], - argsMemoizeOptions: [{ isPromise: false }] - } + { argsMemoizeOptions: [{ isPromise: false }] } ) const selectorDefaultParametric = createSelector( @@ -718,68 +984,103 @@ describe('memoize and argsMemoize', () => { memoizeOptions: [(a, b) => a === b] } ) - assertType< - { - id: number - completed: boolean - }[] - >(selectorDefaultParametric(state, 0)) - assertType< + + expectTypeOf(selectorDefaultParametric(state, 0)).toEqualTypeOf< { id: number completed: boolean }[] - >(selectorDefaultParametric(state, 1)) - // @ts-expect-error - selectorDefaultParametric(state) - // @ts-expect-error - selectorDefaultParametric(1) - // @ts-expect-error - selectorDefaultParametric(state, '') - // @ts-expect-error - selectorDefaultParametric(state, 1, 1) + >() + + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< + [RootState] + >() + + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< + [number] + >() + + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< + [RootState, string] + >() + + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< + [RootState, number, number] + >() + // Checking existence of fields related to `argsMemoize` + // Prior to override, this field did NOT exist. - selectorDefaultParametric.cache + expectTypeOf(selectorDefaultParametric).toHaveProperty('cache').toBeObject() + // Prior to override, this field did NOT exist. - selectorDefaultParametric.fn + expectTypeOf(selectorDefaultParametric).toHaveProperty('fn').toBeObject() + // Prior to override, this field did NOT exist. - selectorDefaultParametric.isMemoized + expectTypeOf(selectorDefaultParametric) + .toHaveProperty('isMemoized') + .toEqualTypeOf(true) + // Prior to override, this field did NOT exist. - selectorDefaultParametric.options - // @ts-expect-error Prior to override, this field DID exist. - selectorDefaultParametric.clearCache() + expectTypeOf(selectorDefaultParametric) + .toHaveProperty('options') + .toBeObject() + + // Prior to override, this field DID exist. + expectTypeOf(selectorDefaultParametric).not.toHaveProperty('clearCache') // Checking existence of fields related to `memoize` - // @ts-expect-error Prior to override, this field DID exist. - selectorDefaultParametric.memoizedResultFunc.clearCache() + + // Prior to override, this field DID exist. + expectTypeOf( + selectorDefaultParametric.memoizedResultFunc + ).not.toHaveProperty('clearCache') + // Prior to override, this field did NOT exist. - selectorDefaultParametric.memoizedResultFunc.clear() + expectTypeOf(selectorDefaultParametric.memoizedResultFunc) + .toHaveProperty('clear') + .toBeFunction() // Checking existence of fields related to the actual memoized selector - assertType< + + expectTypeOf(selectorDefaultParametric.dependencies).toEqualTypeOf< [ (state: RootState, id: number) => number, (state: RootState) => { id: number; completed: boolean }[] ] - >(selectorDefaultParametric.dependencies) - assertType<{ id: number; completed: boolean }[]>( - selectorDefaultParametric.lastResult() + >() + + expectTypeOf(selectorDefaultParametric.lastResult()).toEqualTypeOf< + { + id: number + completed: boolean + }[] + >() + + expectTypeOf(selectorDefaultParametric.memoizedResultFunc) + .parameter(0) + .not.toBeNever() + + expectTypeOf(selectorDefaultParametric.memoizedResultFunc).toBeCallableWith( + 0, + [{ id: 0, completed: true }] ) - assertType<{ id: number; completed: boolean }[]>( + + expectTypeOf( selectorDefaultParametric.memoizedResultFunc(0, [ { id: 0, completed: true } ]) - ) - // @ts-expect-error - selectorDefaultParametric.memoizedResultFunc() - selectorDefaultParametric.recomputations() - selectorDefaultParametric.resetRecomputations() - // @ts-expect-error - selectorDefaultParametric.resultFunc() - assertType<{ id: number; completed: boolean }[]>( - selectorDefaultParametric.resultFunc(0, [{ id: 0, completed: true }]) - ) + ).toEqualTypeOf<{ id: number; completed: boolean }[]>() + + expectTypeOf(selectorDefaultParametric.recomputations).toBeCallableWith() + + expectTypeOf( + selectorDefaultParametric.resetRecomputations + ).toBeCallableWith() + + expectTypeOf(selectorDefaultParametric.resultFunc).toBeCallableWith(0, [ + { id: 0, completed: true } + ]) }) test('memoize And argsMemoize In createSelectorCreator', () => { @@ -796,62 +1097,119 @@ describe('memoize and argsMemoize', () => { (state: RootState) => state.todos, todos => todos.map(({ id }) => id) ) - assertType( + + expectTypeOf( selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault(state) - ) - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.clearCache() - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.cache - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.fn - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.isMemoized - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.options + ).items.toBeNumber() + + expectTypeOf(selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault) + .parameter(0) + .not.toBeNever() + + expectTypeOf(selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault) + .toHaveProperty('resultFunc') + .toBeFunction() + + expectTypeOf(selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault) + .toHaveProperty('clearCache') + .toBeFunction() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault + ).not.toHaveProperty('cache') + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault + ).not.toHaveProperty('fn') + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault + ).not.toHaveProperty('isMemoized') + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault + ).not.toHaveProperty('options') + // Checking existence of fields related to `memoize` - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc - .cache - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc.fn() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc - .isMemoized - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc - .options - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc.clearCache() + expectTypeOf(selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault) + .toHaveProperty('memoizedResultFunc') + .toBeFunction() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc + ) + .toHaveProperty('cache') + .toBeObject() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc + ) + .toHaveProperty('fn') + .toBeFunction() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc + ) + .toHaveProperty('isMemoized') + .toEqualTypeOf(true) + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc + ) + .toHaveProperty('options') + .toBeObject() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc + ).not.toHaveProperty('clearCache') + // Checking existence of fields related to the actual memoized selector - assertType< + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.dependencies + ).toEqualTypeOf< [ (state: RootState) => { id: number completed: boolean }[] ] - >(selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.dependencies) - assertType( + >() + + expectTypeOf( selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.lastResult() + ).items.toBeNumber() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc ) - assertType( - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc( - [{ id: 0, completed: true }] - ) + .parameter(0) + .not.toBeNever() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.recomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resetRecomputations + ).toBeCallableWith() + + expectTypeOf( + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc ) - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.recomputations() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc() - assertType( + .parameter(0) + .not.toBeNever() + + expectTypeOf( selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc([ { id: 0, completed: true } ]) - ) + ).items.toBeNumber() + expectTypeOf( selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoize ).toEqualTypeOf(microMemoize) + expectTypeOf( selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.argsMemoize ).toEqualTypeOf(weakMapMemoize) @@ -873,10 +1231,16 @@ describe('memoize and argsMemoize', () => { { // @ts-expect-error memoize: microMemoize, - // @ts-expect-error - memoizeOptions: { isEqual: (a, b) => a === b }, - // @ts-expect-error - argsMemoizeOptions: { equalityCheck: (a, b) => a === b } + memoizeOptions: { + isEqual: + // @ts-expect-error implicit any + (a, b) => a === b + }, + argsMemoizeOptions: { + equalityCheck: + // @ts-expect-error implicit any + (a, b) => a === b + } }, [] // This causes the error. ) @@ -888,6 +1252,9 @@ describe('memoize and argsMemoize', () => { todos => todos.map(t => t.id), { memoize: autotrackMemoize } ) - selector.memoizedResultFunc.clearCache + + expectTypeOf(selector.memoizedResultFunc) + .toHaveProperty('clearCache') + .toBeFunction() }) }) diff --git a/type-tests/createSelector.test-d.ts b/type-tests/createSelector.test-d.ts new file mode 100644 index 000000000..a66b1fa17 --- /dev/null +++ b/type-tests/createSelector.test-d.ts @@ -0,0 +1,1244 @@ +import { configureStore, createSlice } from '@reduxjs/toolkit' +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' +import memoizeOne from 'memoize-one' +import microMemoize from 'micro-memoize' +import type { TypedUseSelectorHook } from 'react-redux' +import { useSelector } from 'react-redux' +import type { Selector } from 'reselect' +import { createSelector, createSelectorCreator, lruMemoize } from 'reselect' +import type { StateA, StateAB } from '../test/testTypes' + +// Test exporting +export const testExportBasic = createSelector( + (state: StateA) => state.a, + a => a +) + +type Component

= (props: P) => any + +declare function connect( + selector: Selector +): (component: Component

) => Component

+ +describe('type tests', () => { + test('selector', () => { + interface State { + foo: string + } + + const selector = createSelector( + (state: State) => state.foo, + foo => foo + ) + + expectTypeOf(selector.resultFunc).toBeCallableWith('test') + + expectTypeOf(selector.recomputations).toBeFunction() + + expectTypeOf(selector.resetRecomputations).toBeFunction() + + expectTypeOf(selector({ foo: 'bar' })).toBeString() + + expectTypeOf(selector).parameters.not.toHaveProperty('1') + + expectTypeOf(selector({ foo: 'bar' })).not.toBeNumber() + + // allows heterogeneous parameter type input selectors + createSelector( + (state: { foo: string }) => state.foo, + (state: { bar: number }) => state.bar, + (foo, bar) => 1 + ) + + const selectorWithUnions = createSelector( + (state: State, val: string | number) => state.foo, + (state: State, val: string | number) => val, + (foo, val) => val + ) + }) + + test('selector as combiner', () => { + interface SubState { + foo: string + } + + interface State { + bar: SubState + } + + const subSelector = createSelector( + (state: SubState) => state.foo, + foo => foo + ) + + const selector = createSelector((state: State) => state.bar, subSelector) + + expectTypeOf(selector).parameter(0).not.toMatchObjectType<{ foo: '' }>() + + expectTypeOf(selector({ bar: { foo: '' } })).not.toBeNumber() + + expectTypeOf(selector({ bar: { foo: '' } })).toBeString() + }) + + test('connect', () => { + connect( + createSelector( + (state: { foo: string }) => state.foo, + foo => ({ foo }) + ) + )(props => { + expectTypeOf(props).not.toHaveProperty('bar') + + expectTypeOf(props).toHaveProperty('foo').toBeString() + }) + + const selector2 = createSelector( + (state: { foo: string }) => state.foo, + (state: { baz: number }, props: { bar: number }) => props.bar, + (foo, bar) => ({ foo, baz: bar }) + ) + + const connected = connect(selector2)(props => { + expectTypeOf(props).toHaveProperty('foo').toBeString() + + expectTypeOf(props).toHaveProperty('bar').toBeNumber() + + expectTypeOf(props).toHaveProperty('baz').toBeNumber() + + expectTypeOf(props).not.toHaveProperty('fizz') + }) + + expectTypeOf(connected).toBeCallableWith({ bar: 42 }) + + expectTypeOf(connected) + .parameter(0) + .not.toMatchObjectType<{ bar: 42; baz: 123 }>() + }) + + test('invalid type in combiner', () => { + // @ts-expect-error + createSelector( + (state: { foo: string }) => state.foo, + (foo: number) => foo + ) + + createSelector( + (state: { foo: string; bar: number; baz: boolean }) => state.foo, + (state: any) => state.bar, + (state: any) => state.baz, + // @ts-expect-error + (foo: string, bar: number, baz: boolean, fizz: string) => {} + ) + + // does not allow heterogeneous parameter type + // selectors when the combinator function is typed differently + // @ts-expect-error + createSelector( + (state: { testString: string }) => state.testString, + (state: { testNumber: number }) => state.testNumber, + (state: { testBoolean: boolean }) => state.testBoolean, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testNumber: string }) => state.testNumber, + (state: { testStringArray: string[] }) => state.testStringArray, + ( + foo1: string, + foo2: number, + foo3: boolean, + foo4: string, + foo5: string, + foo6: string, + foo7: string, + foo8: number, + foo9: string[] + ) => { + return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } + } + ) + + // does not allow a large array of heterogeneous parameter type + // selectors when the combinator function is typed differently + // @ts-expect-error + createSelector( + [ + (state: { testString: string }) => state.testString, + (state: { testNumber: number }) => state.testNumber, + (state: { testBoolean: boolean }) => state.testBoolean, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testNumber: string }) => state.testNumber, + (state: { testStringArray: string[] }) => state.testStringArray + ], + ( + foo1: string, + foo2: number, + foo3: boolean, + foo4: string, + foo5: string, + foo6: string, + foo7: string, + foo8: number, + foo9: string[] + ) => { + return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } + } + ) + }) + + test('parametric selector', () => { + interface State { + foo: string + } + + interface Props { + bar: number + } + + // allows heterogeneous parameter type selectors + const selector1 = createSelector( + (state: { testString: string }) => state.testString, + (state: { testNumber: number }) => state.testNumber, + (state: { testBoolean: boolean }) => state.testBoolean, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testStringArray: string[] }) => state.testStringArray, + ( + foo1: string, + foo2: number, + foo3: boolean, + foo4: string, + foo5: string, + foo6: string, + foo7: string, + foo8: string, + foo9: string[] + ) => { + return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } + } + ) + + expectTypeOf(selector1).toBeCallableWith({ + testString: 'a', + testNumber: 42, + testBoolean: true, + testStringArray: ['b', 'c'] + }) + + const selector = createSelector( + (state: State) => state.foo, + (state: State, props: Props) => props.bar, + (foo, bar) => ({ foo, bar }) + ) + + // @ts-expect-error + selector({ foo: 'fizz' }) + // @ts-expect-error + selector({ foo: 'fizz' }, { bar: 'baz' }) + + const ret = selector({ foo: 'fizz' }, { bar: 42 }) + + expectTypeOf(ret).toHaveProperty('foo').toBeString() + + expectTypeOf(ret).toHaveProperty('bar').toBeNumber() + + const selector2 = createSelector( + (state: State) => state.foo, + (state: State) => state.foo, + (state: State) => state.foo, + (state: State) => state.foo, + (state: State) => state.foo, + (state: State, props: Props) => props.bar, + (foo1, foo2, foo3, foo4, foo5, bar) => ({ + foo1, + foo2, + foo3, + foo4, + foo5, + bar + }) + ) + + expectTypeOf(selector2).toBeCallableWith({ foo: 'fizz' }, { bar: 42 }) + + const selector3 = createSelector( + (s: State) => s.foo, + (s: State, x: string) => x, + (s: State, y: number) => y, + (v, x) => { + return x + v + } + ) + + expectTypeOf(selector3).parameter(1).toBeNever() + + const selector4 = createSelector( + (s: State, val: number) => s.foo, + (s: State, val: string | number) => val, + (foo, val) => { + return val + } + ) + + expectTypeOf(selector4).toBeCallableWith({ foo: 'fizz' }, 42) + }) + + test('array argument', () => { + const selector = createSelector( + [ + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }, props: { bar: number }) => props.bar + ], + (foo1, foo2, bar) => ({ foo1, foo2, bar }) + ) + + const ret = selector({ foo: 'fizz' }, { bar: 42 }) + + expectTypeOf(ret).toHaveProperty('foo1').toBeString() + + expectTypeOf(ret).toHaveProperty('foo2').toBeString() + + expectTypeOf(ret).toHaveProperty('bar').toBeNumber() + + // @ts-expect-error + createSelector([(state: { foo: string }) => state.foo]) + + // @ts-expect-error + createSelector( + [ + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo + ], + (foo: string, bar: number) => {} + ) + + createSelector( + [ + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo + ], + ( + foo1: string, + foo2: string, + foo3: string, + foo4: string, + foo5: string, + foo6: string, + foo7: string, + foo8: string, + foo9: string, + foo10: string + ) => {} + ) + + // @ts-expect-error + createSelector( + [ + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo + ], + ( + foo1, + foo2, + foo3, + foo4, + foo5, + foo6, + foo7, + foo8: number, + foo9, + foo10 + ) => {} + ) + + // @ts-expect-error + createSelector( + [ + (state: { foo: string }) => state.foo, + // @ts-expect-error + state => state.foo, + // @ts-expect-error + state => state.foo, + // @ts-expect-error + state => state.foo, + // @ts-expect-error + state => state.foo, + // @ts-expect-error + state => state.foo, + // @ts-expect-error + state => state.foo, + // @ts-expect-error + state => state.foo, + 1 + ], + // We expect an error here, but the error differs between TS versions + // @ts-ignore + (foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9) => {} + ) + + const selector2 = createSelector( + [ + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo + ], + ( + foo1: string, + foo2: string, + foo3: string, + foo4: string, + foo5: string, + foo6: string, + foo7: string, + foo8: string, + foo9: string + ) => { + return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } + } + ) + + { + const ret = selector2({ foo: 'fizz' }) + + expectTypeOf(ret).toHaveProperty('foo1').toBeString() + + expectTypeOf(ret).toHaveProperty('foo2').toBeString() + + expectTypeOf(ret).toHaveProperty('foo3').toBeString() + + expectTypeOf(ret).toHaveProperty('foo4').toBeString() + + expectTypeOf(ret).toHaveProperty('foo5').toBeString() + + expectTypeOf(ret).toHaveProperty('foo6').toBeString() + + expectTypeOf(ret).toHaveProperty('foo7').toBeString() + + expectTypeOf(ret).toHaveProperty('foo8').toBeString() + + expectTypeOf(ret).toHaveProperty('foo9').toBeString() + + expectTypeOf(ret).not.toHaveProperty('foo10') + } + + expectTypeOf(selector2).parameters.not.toHaveProperty('1') + + const parametric = createSelector( + [ + (state: { foo: string }, props: { bar: number }) => props.bar, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo + ], + ( + bar: number, + foo1: string, + foo2: string, + foo3: string, + foo4: string, + foo5: string, + foo6: string, + foo7: string, + foo8: string + ) => { + return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, bar } + } + ) + + // allows a large array of heterogeneous parameter type selectors + const correctlyTypedArraySelector = createSelector( + [ + (state: { testString: string }) => state.testString, + (state: { testNumber: number }) => state.testNumber, + (state: { testBoolean: boolean }) => state.testBoolean, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testString: string }) => state.testString, + (state: { testStringArray: string[] }) => state.testStringArray + ], + ( + foo1: string, + foo2: number, + foo3: boolean, + foo4: string, + foo5: string, + foo6: string, + foo7: string, + foo8: string, + foo9: string[] + ) => { + return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } + } + ) + + // @ts-expect-error + parametric({ foo: 'fizz' }) + + { + const ret = parametric({ foo: 'fizz' }, { bar: 42 }) + + expectTypeOf(ret).toHaveProperty('foo1').toBeString() + + expectTypeOf(ret).toHaveProperty('foo2').toBeString() + + expectTypeOf(ret).toHaveProperty('foo3').toBeString() + + expectTypeOf(ret).toHaveProperty('foo4').toBeString() + + expectTypeOf(ret).toHaveProperty('foo5').toBeString() + + expectTypeOf(ret).toHaveProperty('foo6').toBeString() + + expectTypeOf(ret).toHaveProperty('foo7').toBeString() + + expectTypeOf(ret).toHaveProperty('foo8').toBeString() + + expectTypeOf(ret).toHaveProperty('bar').toBeNumber() + + expectTypeOf(ret).not.toHaveProperty('foo9') + } + }) + + test('optional arguments conflicting', () => { + interface State { + foo: string + bar: number + baz: boolean + } + + const selector = createSelector( + (state: State) => state.baz, + (state: State, arg: string) => arg, + (state: State, arg: number) => arg, + baz => { + expectTypeOf(baz).toBeBoolean() + + expectTypeOf(baz).not.toBeNumber() + } + ) + + // @ts-expect-error the selector above has inconsistent conflicting arguments so usage should error + selector({} as State) + // @ts-expect-error + selector({} as State, 'string') + // @ts-expect-error + selector({} as State, 1) + + const selector2 = createSelector( + (state: State, prefix: any) => prefix + state.foo, + str => str + ) + + // @ts-expect-error here we require one argument which can be anything so error if there are no arguments + selector2({} as State) + // no error passing anything in + selector2({} as State, 'blach') + selector2({} as State, 1) + + // here the argument is optional so it should be possible to omit the argument or pass anything + const selector3 = createSelector( + (state: State, prefix?: any) => prefix + state.foo, + str => str + ) + + selector3({} as State) + selector3({} as State, 1) + selector3({} as State, 'blach') + + // https://github.com/reduxjs/reselect/issues/563 + const selector4 = createSelector( + (state: State, prefix: string, suffix: any) => + prefix + state.foo + String(suffix), + str => str + ) + + // @ts-expect-error + selector4({} as State) + // @ts-expect-error + selector4({} as State, 'blach') + + expectTypeOf(selector4).toBeCallableWith({} as State, 'blach', 4) + + // as above but a unknown 2nd argument + const selector5 = createSelector( + (state: State, prefix: string, suffix: unknown) => + prefix + state.foo + String(suffix), + str => str + ) + + // @ts-expect-error + selector5({} as State) + // @ts-expect-error + selector5({} as State, 'blach') + + expectTypeOf(selector5).toBeCallableWith({} as State, 'blach', 4) + + // this is an example fixing selector6. We have to add a un-necessary typing in and magically the types are correct + const selector7 = createSelector( + (state: State, prefix: string = 'a') => prefix + state.foo, + (str: string) => str + ) + + expectTypeOf(selector7).toBeCallableWith({} as State) + + expectTypeOf(selector7).toBeCallableWith({} as State, 'blach') + + // @ts-expect-error wrong type + selector7({} as State, 1) + + const selector8 = createSelector( + (state: State, prefix: unknown) => prefix, + str => str + ) + + // @ts-expect-error needs a argument + selector8({} as State) + + // allowed to pass anything as the type is unknown + expectTypeOf(selector8).toBeCallableWith({} as State, 'blach') + + expectTypeOf(selector8).toBeCallableWith({} as State, 2) + }) + + test('dynamic array argument', () => { + interface Elem { + val1: string + val2: string + } + const data: ReadonlyArray = [ + { val1: 'a', val2: 'aa' }, + { val1: 'b', val2: 'bb' } + ] + + createSelector( + data.map(obj => () => obj.val1), + (...vals) => vals.join(',') + ) + + createSelector( + data.map(obj => () => obj.val1), + // @ts-expect-error + vals => vals.join(',') + ) + + createSelector( + data.map(obj => () => obj.val1), + (...vals: string[]) => 0 + ) + // @ts-expect-error + createSelector( + data.map(obj => () => obj.val1), + (...vals: number[]) => 0 + ) + + const s = createSelector( + data.map(obj => (state: StateA, fld: keyof Elem) => obj[fld]), + (...vals) => vals.join(',') + ) + s({ a: 42 }, 'val1') + s({ a: 42 }, 'val2') + // @ts-expect-error + s({ a: 42 }, 'val3') + }) + + test('issue #445: Typescript validation issues when passing function to combiner', () => { + // https://github.com/reduxjs/reselect/issues/445 + + interface TestState { + someNumber: number | null + someString: string | null + } + + interface Object1 { + str: string + } + interface Object2 { + num: number + } + + const getNumber = (state: TestState) => state.someNumber + const getString = (state: TestState) => state.someString + + function generateObject1(str: string): Object1 { + return { + str + } + } + function generateObject2(num: number): Object2 { + return { + num + } + } + function generateComplexObject( + num: number, + subObject: Object1, + subObject2: Object2 + ): boolean { + return true + } + + // ################ Tests ################ + + // Compact selector examples + + // Should error because generateObject1 can't take null + // @ts-expect-error + const getObject1 = createSelector([getString], generateObject1) + + // Should error because generateObject2 can't take null + // @ts-expect-error + const getObject2 = createSelector([getNumber], generateObject2) + + // Should error because mismatch of params + // @ts-expect-error + const getComplexObjectTest1 = createSelector( + [getObject1], + generateComplexObject + ) + + // Does error, but error is really weird and talks about "Object1 is not assignable to type number" + // @ts-expect-error + const getComplexObjectTest2 = createSelector( + [getNumber, getObject1], + generateComplexObject + ) + + // Should error because number can't be null + // @ts-expect-error + const getComplexObjectTest3 = createSelector( + [getNumber, getObject1, getObject2], + generateComplexObject + ) + + // Does error, but error is really weird and talks about "Object1 is not assignable to type number" + // @ts-expect-error + const getComplexObjectTest4 = createSelector( + [getObject1, getNumber, getObject2], + generateComplexObject + ) + + // Verbose selector examples + + // Errors correctly, says str can't be null + const getVerboseObject1 = createSelector([getString], str => + // @ts-expect-error + generateObject1(str) + ) + + // Errors correctly, says num can't be null + const getVerboseObject2 = createSelector([getNumber], num => + // @ts-expect-error + generateObject2(num) + ) + + // Errors correctly + const getVerboseComplexObjectTest1 = createSelector([getObject1], obj1 => + // @ts-expect-error + generateComplexObject(obj1) + ) + + // Errors correctly + const getVerboseComplexObjectTest2 = createSelector( + [getNumber, getObject1], + // @ts-expect-error + (num, obj1) => generateComplexObject(num, obj1) + ) + + // Errors correctly + const getVerboseComplexObjectTest3 = createSelector( + [getNumber, getObject1, getObject2], + // @ts-expect-error + (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) + ) + + // Errors correctly + const getVerboseComplexObjectTest4 = createSelector( + [getObject1, getNumber, getObject2], + // @ts-expect-error + (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) + ) + }) + + test('issue #492: Props argument types not merged correctly with overlapping keys', () => { + // https://github.com/reduxjs/reselect/issues/492 + + const fooPropSelector = (_: {}, ownProps: { foo: string }) => ownProps.foo + const fooBarPropsSelector = ( + _: {}, + ownProps: { foo: string; bar: string } + ) => [ownProps.foo, ownProps.bar] + + const combinedSelector = createSelector( + fooPropSelector, + fooBarPropsSelector, + (foo, fooBar) => fooBar + ) + }) + + test('ensure that input selectors with mismatched states raise errors', () => { + const input1 = (state: string) => 1 + const input2 = (state: number) => 2 + + const selector = createSelector(input1, input2, (...args) => 0) + // @ts-expect-error + selector('foo') + // @ts-expect-error + selector(5) + + const selector1 = createSelector( + (state: { foo: string }) => 1, + (state: { bar: string }) => 2, + (...args) => 0 + ) + selector1({ foo: '', bar: '' }) + // @ts-expect-error + selector1({ foo: '' }) + // @ts-expect-error + selector1({ bar: '' }) + + const selector2 = createSelector( + (state: { foo: string }) => 1, + (state: { foo: string }) => 2, + (...args) => 0 + ) + // @ts-expect-error + selector2({ foo: '', bar: '' }) + selector2({ foo: '' }) + // @ts-expect-error + selector2({ bar: '' }) + }) + + test('issue #526: input selector with undefined return', () => { + // https://github.com/reduxjs/reselect/issues/526 + + interface Input { + field: number | undefined + } + + type Output = string + + type SelectorType = (input: Input) => Output + + const input = ({ field }: Input) => field + + const result = (out: number | undefined): Output => 'test' + + // Make sure the selector type is honored + const selector: SelectorType = createSelector( + ({ field }: Input) => field, + args => 'test' + ) + + // even when memoizeOptions are passed + const selector2: SelectorType = createSelector( + ({ field }: Input) => field, + args => 'test', + { + memoize: lruMemoize, + memoizeOptions: { maxSize: 42 } + } + ) + + // Make sure inference of functions works... + const selector3: SelectorType = createSelector(input, result) + const selector4: SelectorType = createSelector(input, result, { + memoize: lruMemoize, + memoizeOptions: { maxSize: 42 } + }) + }) + + test('issue #540: Multiple selectors with arguments result in a union type', () => { + // https://github.com/reduxjs/reselect/issues/540 + + const input1 = ( + _: StateA, + { testNumber }: { testNumber: number }, + c: number, + d: string + ) => testNumber + + const input2 = ( + _: StateA, + { testString }: { testString: string }, + c: number | string + ) => testString + + const input3 = ( + _: StateA, + { testBoolean }: { testBoolean: boolean }, + c: number | string, + d: string + ) => testBoolean + + const input4 = (_: StateA, { testString2 }: { testString2: string }) => + testString2 + + const testSelector = createSelector( + input1, + input2, + input3, + input4, + (testNumber, testString, testBoolean) => testNumber + testString + ) + + const state: StateA = { a: 42 } + const test = testSelector( + state, + { + testNumber: 1, + testString: '10', + testBoolean: true, + testString2: 'blah' + }, + 42, + 'blah' + ) + + // #541 + const selectProp1 = createSelector( + [ + (state: StateA) => state, + (state: StateA, props: { prop1: number }) => props + ], + (state, { prop1 }) => [state, prop1] + ) + + const selectProp2 = createSelector( + [selectProp1, (state, props: { prop2: number }) => props], + (state, { prop2 }) => [state, prop2] + ) + + selectProp1({ a: 42 }, { prop1: 1 }) + // @ts-expect-error + selectProp2({ a: 42 }, { prop2: 2 }) + }) + + test('issue #550: createSelector accepts selectors with more than one parameter', () => { + // https://github.com/reduxjs/reselect/issues/550 + + const some = createSelector( + (a: number) => a, + (_a: number, b: number) => b, + (a, b) => a + b + ) + + const test = some(1, 2) + }) + + test('RTK issue #1750: Type conflicts with TypedUseSelectorHook', () => { + // https://github.com/reduxjs/redux-toolkit/issues/1750 + + const slice = createSlice({ + name: 'test', + initialState: 0, + reducers: {} + }) + + interface Pokemon { + name: string + } + + // Define a service using a base URL and expected endpoints + const pokemonApi = createApi({ + reducerPath: 'pokemonApi', + baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }), + endpoints: builder => ({ + getPokemonByName: builder.query({ + query: name => `pokemon/${name}` + }) + }) + }) + + const store = configureStore({ + reducer: { + test: slice.reducer, + [pokemonApi.reducerPath]: pokemonApi.reducer + }, + middleware: getDefaultMiddleware => + getDefaultMiddleware().concat(pokemonApi.middleware) + }) + + type RootState = ReturnType + + const selectTest = createSelector( + (state: RootState) => state.test, + test => test + ) + + const useAppSelector: TypedUseSelectorHook = useSelector + + // Selector usage should compile correctly + const testItem = selectTest(store.getState()) + + function App() { + const test = useAppSelector(selectTest) + return null + } + }) + + test('handle nested incompatible types', () => { + // Incompatible parameters should force errors even for nested fields. + // One-level-deep fields get stripped to empty objects, so they + // should be replaced with `never`. + // Deeper fields should get caught by TS. + // Playground: https://tsplay.dev/wg6X0W + const input1a = (_: StateA, param: { b: number }) => param.b + + const input1b = (_: StateA, param: { b: string }) => param.b + + const testSelector1 = createSelector(input1a, input1b, () => ({})) + + // @ts-expect-error + testSelector1({ a: 42 }, { b: 99 }) // should not compile + + const input2a = (_: StateA, param: { b: { c: number } }) => param.b.c + const input2b = (_: StateA, param: { b: { c: string } }) => param.b.c + + const testSelector2 = createSelector(input2a, input2b, (c1, c2) => {}) + + // @ts-expect-error + testSelector2({ a: 42 }, { b: { c: 99 } }) + }) + + test('issue #554a: createSelector should support undefined and optional parameters', () => { + // https://github.com/reduxjs/reselect/issues/554 + + interface State { + foo: string + bar: number + } + + const initialState: State = { + foo: 'This is Foo', + bar: 1 + } + + const getFoo = (state: State) => { + return state.foo + } + getFoo(initialState) + + const getBar = (state: State) => { + return state.bar + } + getBar(initialState) + + const simple = createSelector(getFoo, getBar, (foo, bar) => { + return `${foo} => ${bar}` + }) + simple(initialState) + + // Input selectors with positional args + const firstInput = (_: State, first: string) => first + // Skip the first arg and return only the second. + const secondInput = (_: State, _first: string, second: number) => second + + const complexOne = createSelector( + getFoo, + getBar, + firstInput, + (foo, bar, first) => { + return `${foo} => ${bar} || ${first}` + } + ) + complexOne(initialState, 'first') + + const complexTwo = createSelector( + getFoo, + getBar, + firstInput, + secondInput, + (foo, bar, first, second) => { + return `${foo} => ${bar} || ${first} and ${second}` + } + ) + // TS should complain since 'second' should be `number` + // @ts-expect-error + complexTwo(initialState, 'first', 'second') + }) + + test('issue #554b: createSelector should support undefined and optional parameters', () => { + // https://github.com/reduxjs/reselect/issues/554 + + interface State { + counter1: number + counter2: number + } + + const selectTest = createSelector( + (state: State, numberA?: number) => numberA, + (state: State) => state.counter2, + (numberA, counter2) => (numberA ? numberA + counter2 : counter2) + ) + + type selectTestParams = Parameters + const p1: selectTestParams = [{ counter1: 1, counter2: 2 }, 42] + + expectTypeOf(p1).toEqualTypeOf<[State, number?]>() + + const result = selectTest({ counter1: 1, counter2: 2 }, 42) + }) + + test('issue #554c: createSelector should support undefined and optional parameters', () => { + // https://github.com/reduxjs/reselect/issues/554 + + interface State { + counter1: number + counter2: number + } + + const selectTest = createSelector( + (state: State, numberA?: number) => numberA, // `numberA` is optional + (state: State) => state.counter2, + (numberA, counter2) => (numberA ? numberA + counter2 : counter2) + ) + + // @ts-expect-error + const value = selectTest({ counter1: 0, counter2: 0 }, 'what?') + + const selectTest2 = createSelector( + (state: State, numberA: number) => numberA, // `numberA` is not optional anymore + (state: State) => state.counter2, + (numberA, counter2) => (numberA ? numberA + counter2 : counter2) + ) + + // @ts-expect-error + const value2 = selectTest2({ counter1: 0, counter2: 0 }, 'what?') + }) + + test('issue #555: createSelector should support undefined, null and optional parameters', () => { + // https://github.com/reduxjs/reselect/issues/555 + + interface IReduxState { + ui: { + x: string + y: string + } + } + + const someSelector1 = createSelector( + (state: IReduxState, param: 'x' | 'y' | undefined) => + param !== undefined ? state.ui[param] : null, + (a: string | null) => a + ) + + const someSelector2 = createSelector( + (state: IReduxState, param?: 'x' | 'y') => + param !== undefined ? state.ui[param] : null, + (a: string | null) => a + ) + + const someSelector3 = createSelector( + (state: IReduxState, param: 'x' | 'y' | null) => + param !== null ? state.ui[param] : null, + (a: string | null) => a + ) + + const state = { ui: { x: '1', y: '2' } } + + const selectorResult1 = someSelector1(state, undefined) + const selectorResult2 = someSelector2(state, undefined) + const selectorResult3 = someSelector3(state, null) + }) + + test('config options', () => { + const lruMemoizeAcceptsFirstArgDirectly = createSelector( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoize: lruMemoize, + memoizeOptions: (a, b) => a === b + } + ) + + const lruMemoizeAcceptsFirstArgAsObject = createSelector( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoize: lruMemoize, + memoizeOptions: { + equalityCheck: (a, b) => a === b + } + } + ) + + const lruMemoizeAcceptsArgsAsArray = createSelector( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoize: lruMemoize, + memoizeOptions: [(a, b) => a === b] + } + ) + + const customSelectorCreatorMicroMemoize = createSelectorCreator( + microMemoize, + { + maxSize: 42 + } + ) + + customSelectorCreatorMicroMemoize( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoizeOptions: [ + { + maxSize: 42 + } + ] + } + ) + + const customSelectorCreatorMemoizeOne = createSelectorCreator(memoizeOne) + + customSelectorCreatorMemoizeOne( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoizeOptions: (a, b) => a === b + } + ) + }) +}) diff --git a/type-tests/createSelector.withTypes.test-d.ts b/type-tests/createSelector.withTypes.test-d.ts index c3e00618e..6840e3d3b 100644 --- a/type-tests/createSelector.withTypes.test-d.ts +++ b/type-tests/createSelector.withTypes.test-d.ts @@ -27,7 +27,7 @@ const rootState: RootState = { ] } -describe('createSelector.withTypes()', () => { +describe('type tests', () => { const createAppSelector = createSelector.withTypes() describe('when input selectors are provided as a single array', () => { @@ -41,13 +41,13 @@ describe('createSelector.withTypes()', () => { createAppSelector( [ state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos } ], todos => { - expectTypeOf(todos).toEqualTypeOf(rootState.todos) + expectTypeOf(todos).toEqualTypeOf() return todos.map(({ id }) => id) } @@ -60,21 +60,22 @@ describe('createSelector.withTypes()', () => { // Type of state is locked but the parameter types of the // result function are NOT correctly inferred when // input selectors are provided as separate inline arguments. + // NOTE: In TypeScript versions prior to 5.1, `withTypes` works correctly + // only when input selectors are provided as a single array. createAppSelector( - state => { - expectTypeOf(state).toEqualTypeOf(rootState) + [ + state => { + expectTypeOf(state).toEqualTypeOf(rootState) - return state.todos - }, + return state.todos + } + ], todos => { // Known limitation: Parameter types are not inferred in this scenario - expectTypeOf(todos).toBeAny() + expectTypeOf(todos).not.toBeAny() - expectTypeOf(todos).not.toEqualTypeOf(rootState.todos) + expectTypeOf(todos).toEqualTypeOf() - // @ts-expect-error A typed `createSelector` currently only infers - // the parameter types of the result function when - // input selectors are provided as a single array. return todos.map(({ id }) => id) } ) @@ -84,34 +85,32 @@ describe('createSelector.withTypes()', () => { // Checking to see if the type of state is correct when multiple // input selectors are provided as separate inline arguments. createAppSelector( - state => { - expectTypeOf(state).toEqualTypeOf(rootState) + [ + state => { + expectTypeOf(state).toEqualTypeOf(rootState) - return state.todos - }, - state => { - expectTypeOf(state).toEqualTypeOf(rootState) + return state.todos + }, + state => { + expectTypeOf(state).toEqualTypeOf(rootState) - return state.alerts - }, + return state.alerts + } + ], (todos, alerts) => { // Known limitation: Parameter types are not inferred in this scenario - expectTypeOf(todos).toBeAny() + expectTypeOf(todos).not.toBeAny() - expectTypeOf(alerts).toBeAny() + expectTypeOf(alerts).not.toBeAny() - // @ts-expect-error A typed `createSelector` currently only infers - // the parameter types of the result function when - // input selectors are provided as a single array. return todos.map(({ id }) => id) } ) }) test('can annotate parameter types of the result function to workaround type inference issue', () => { - createAppSelector( - state => state.todos, - (todos: Todo[]) => todos.map(({ id }) => id) + createAppSelector([state => state.todos], todos => + todos.map(({ id }) => id) ) }) }) diff --git a/type-tests/createSelectorCreator.test-d.ts b/type-tests/createSelectorCreator.test-d.ts index 76f358b0a..ff09807c2 100644 --- a/type-tests/createSelectorCreator.test-d.ts +++ b/type-tests/createSelectorCreator.test-d.ts @@ -1,14 +1,21 @@ +import type { AnyFunction } from '@internal/types' import lodashMemoize from 'lodash/memoize' import memoizeOne from 'memoize-one' import microMemoize from 'micro-memoize' import { + unstable_autotrackMemoize as autotrackMemoize, createSelectorCreator, lruMemoize, - unstable_autotrackMemoize as autotrackMemoize, weakMapMemoize } from 'reselect' import { describe, test } from 'vitest' +// Test for exporting declaration of created selector creator +export const testExportStructured = createSelectorCreator( + lruMemoize, + (a, b) => typeof a === typeof b +) + interface RootState { todos: { id: number; completed: boolean }[] alerts: { id: number; read: boolean }[] @@ -25,7 +32,7 @@ const state: RootState = { ] } -describe('createSelectorCreator', () => { +describe('type tests', () => { test('options object as argument', () => { const createSelectorDefault = createSelectorCreator({ memoize: lruMemoize @@ -55,4 +62,67 @@ describe('createSelectorCreator', () => { const createSelectorOne = createSelectorCreator(memoizeOne) const createSelectorLodash = createSelectorCreator(lodashMemoize) }) + + test('createSelectorCreator', () => { + const defaultCreateSelector = createSelectorCreator(lruMemoize) + + const selector = defaultCreateSelector( + (state: { foo: string }) => state.foo, + foo => foo + ) + + expectTypeOf(selector({ foo: 'fizz' })).toBeString() + + expectTypeOf(selector).parameter(1).not.toMatchObjectType<{ bar: 42 }>() + + // clearCache should exist because of lruMemoize + expectTypeOf(selector.clearCache).toBeFunction() + + const parametric = defaultCreateSelector( + (state: { foo: string }) => state.foo, + (state: { foo: string }, props: { bar: number }) => props.bar, + (foo, bar) => ({ foo, bar }) + ) + + // @ts-expect-error + parametric({ foo: 'fizz' }) + + const ret = parametric({ foo: 'fizz' }, { bar: 42 }) + + expectTypeOf(ret.foo).toBeString() + + expectTypeOf(ret.bar).toBeNumber() + + // @ts-expect-error + createSelectorCreator(lruMemoize, 1) + + createSelectorCreator(lruMemoize, (a: T, b: T) => { + return `${a}` === `${b}` + }) + }) + + test('custom memoization option types', () => { + const customMemoize = ( + f: AnyFunction, + a: string, + b: number, + c: boolean + ) => { + return f + } + + const customSelectorCreatorCustomMemoizeWorking = createSelectorCreator( + customMemoize, + 'a', + 42, + true + ) + + // @ts-expect-error + const customSelectorCreatorCustomMemoizeMissingArg = createSelectorCreator( + customMemoize, + 'a', + true + ) + }) }) diff --git a/type-tests/createStructuredSelector.test-d.ts b/type-tests/createStructuredSelector.test-d.ts index e7398f476..201c5548f 100644 --- a/type-tests/createStructuredSelector.test-d.ts +++ b/type-tests/createStructuredSelector.test-d.ts @@ -1,12 +1,14 @@ import microMemoize from 'micro-memoize' import type { Selector, TypedStructuredSelectorCreator } from 'reselect' import { + createSelector, createSelectorCreator, createStructuredSelector, lruMemoize, weakMapMemoize } from 'reselect' import { describe, expectTypeOf, test } from 'vitest' +import type { StateAB } from '../test/testTypes' interface Todo { id: number @@ -34,8 +36,7 @@ const rootState: RootState = { ] } -describe('createStructuredSelector', () => { - +describe('type tests', () => { // TODO: Remove this test block once `TypedStructuredSelectorCreator` is removed. test('TypedStructuredSelectorCreator should lock down state type', () => { const createStructuredAppSelector: TypedStructuredSelectorCreator = @@ -43,12 +44,12 @@ describe('createStructuredSelector', () => { const structuredSelector = createStructuredAppSelector({ todos: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, alerts: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.alerts } @@ -60,13 +61,9 @@ describe('createStructuredSelector', () => { expectTypeOf(alerts).toEqualTypeOf() - expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf(weakMapMemoize) - expectTypeOf(structuredSelector.memoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredSelector.memoize).toEqualTypeOf(weakMapMemoize) expectTypeOf(structuredSelector.clearCache).returns.toBeVoid() @@ -90,28 +87,23 @@ describe('createStructuredSelector', () => { () => void >() - expectTypeOf( - structuredSelector.lastResult - ).returns.toEqualTypeOf(rootState) + expectTypeOf(structuredSelector.lastResult).returns.toEqualTypeOf(rootState) expectTypeOf( structuredSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[]]>([ - rootState.todos, - rootState.alerts - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[]]>() - expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) }) // TODO: Remove this test block once `TypedStructuredSelectorCreator` is removed. @@ -132,13 +124,9 @@ describe('createStructuredSelector', () => { createSelectorLru ) - expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf< - typeof microMemoize - >(microMemoize) + expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf(microMemoize) - expectTypeOf(structuredSelector.memoize).toEqualTypeOf( - lruMemoize - ) + expectTypeOf(structuredSelector.memoize).toEqualTypeOf(lruMemoize) const { todos, alerts } = structuredSelector(rootState) @@ -164,28 +152,23 @@ describe('createStructuredSelector', () => { () => void >() - expectTypeOf( - structuredSelector.lastResult - ).returns.toEqualTypeOf(rootState) + expectTypeOf(structuredSelector.lastResult).returns.toEqualTypeOf(rootState) expectTypeOf( structuredSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[]]>([ - rootState.todos, - rootState.alerts - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[]]>() - expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) }) test('supports additional parameters', () => { @@ -203,19 +186,15 @@ describe('createStructuredSelector', () => { expectTypeOf(todoById).toEqualTypeOf() - expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf(weakMapMemoize) - expectTypeOf(structuredSelector.memoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredSelector.memoize).toEqualTypeOf(weakMapMemoize) expectTypeOf(structuredSelector.clearCache).returns.toBeVoid() expectTypeOf(structuredSelector.clearCache).parameters.toEqualTypeOf<[]>() - expectTypeOf(structuredSelector.dependencies).items.toMatchTypeOf< + expectTypeOf(structuredSelector.dependencies).items.toExtend< Selector >() @@ -248,26 +227,183 @@ describe('createStructuredSelector', () => { expectTypeOf( structuredSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[], Todo]>([ - rootState.todos, - rootState.alerts, - rootState.todos[0] - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[], Todo]>() expectTypeOf(structuredSelector.resultFunc).parameters.toEqualTypeOf< [Todo[], Alert[], Todo] - >([rootState.todos, rootState.alerts, rootState.todos[0]]) + >() - expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) + }) + + test('automatic inference of types for createStructuredSelector', () => { + const oneParamSelector = createStructuredSelector({ + foo: (state: StateAB) => state.a, + bar: (state: StateAB) => state.b + }) + + const threeParamSelector = createStructuredSelector({ + foo: (state: StateAB, c: number, d: string) => state.a, + bar: (state: StateAB, c: number, d: string) => state.b + }) + + interface State { + foo: string + } + + const FooSelector = (state: State, a: number, b: string) => state.foo + const BarSelector = (state: State, a: number, b: string) => +state.foo + + const selector2 = createStructuredSelector({ + foo: FooSelector, + bar: BarSelector + }) + + const selectorGenerics = createStructuredSelector<{ + foo: typeof FooSelector + bar: typeof BarSelector + }>({ + foo: state => state.foo, + bar: state => +state.foo + }) + + interface ExpectedResult { + foo: string + bar: number + } + + const resOneParam = oneParamSelector({ a: 1, b: 2 }) + const resThreeParams = threeParamSelector({ a: 1, b: 2 }, 99, 'blah') + const res3: ExpectedResult = selector2({ foo: '42' }, 99, 'test') + const resGenerics: ExpectedResult = selectorGenerics( + { foo: '42' }, + 99, + 'test' + ) + + //@ts-expect-error + selector2({ bar: '42' }) + // @ts-expect-error + selectorGenerics({ bar: '42' }) + }) + + test('structured selector type parameters', () => { + interface GlobalState { + foo: string + bar: number + } + + const selectFoo = (state: GlobalState) => state.foo + const selectBar = (state: GlobalState) => state.bar + + // Output state should be the same as input, if not provided + // @ts-expect-error + createStructuredSelector({ + foo: selectFoo + // bar: selectBar, + // ^^^ because this is missing, an error is thrown + }) + }) + + test("issue #548: createStructuredSelector doesn't infer props typings", () => { + // https://github.com/reduxjs/reselect/issues/548 + + interface State { + value: Record | null + loading: boolean + } + + interface Props { + currency: string + } + + const isLoading = createSelector( + (state: State) => state, + (_: State, props: Props) => props.currency, + ({ loading }, currency) => loading + ) + + const mapData = createStructuredSelector({ + isLoading, + test2: (state: State) => 42 + }) + + const result = mapData({ value: null, loading: false }, { currency: 'EUR' }) + }) + + test('verify structured selector matches createSelector in output structure and type definitions', () => { + // A structured selector created by `createStructuredSelector` + // is the same as a selector created by `createSelector` when it + // returns an object made up of selectors + + const createSelectorMicro = createSelectorCreator({ + memoize: microMemoize, + argsMemoize: microMemoize + }) + + const selector = createSelectorMicro( + [ + (state: RootState) => state.todos, + (state: RootState) => state.alerts, + (state: RootState, id: number) => state.todos[id] + ], + (todos, alerts, todoById) => ({ todos, alerts, todoById }) + ) + + const structuredSelector = createStructuredSelector( + { + todos: (state: RootState) => state.todos, + alerts: (state: RootState) => state.alerts, + todoById: (state: RootState, id: number) => state.todos[id] + }, + + createSelectorMicro + ) + + expectTypeOf(structuredSelector).toEqualTypeOf(selector) + + expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty('cache') + + expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty('fn') + + expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty( + 'isMemoized' + ) + + expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty( + 'options' + ) + expectTypeOf(selector.memoizedResultFunc).toHaveProperty('cache') + + expectTypeOf(selector.memoizedResultFunc).toHaveProperty('fn') + + expectTypeOf(selector.memoizedResultFunc).toHaveProperty('isMemoized') + + expectTypeOf(selector.memoizedResultFunc).toHaveProperty('options') + + expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf(microMemoize) + + expectTypeOf(structuredSelector.memoize).toEqualTypeOf(microMemoize) + + expectTypeOf(structuredSelector.dependencies).toEqualTypeOf< + [ + (state: RootState) => Todo[], + (state: RootState) => Alert[], + (state: RootState, id: number) => Todo + ] + >() + + // @ts-expect-error Wrong number of arguments. + structuredSelector(state, 2) }) }) diff --git a/type-tests/createStructuredSelector.withTypes.test-d.ts b/type-tests/createStructuredSelector.withTypes.test-d.ts index 9bb5b1ff7..a3af33e2b 100644 --- a/type-tests/createStructuredSelector.withTypes.test-d.ts +++ b/type-tests/createStructuredSelector.withTypes.test-d.ts @@ -39,7 +39,7 @@ const rootState: RootState = { ] } -describe('createStructuredSelector.withTypes()', () => { +describe('type tests', () => { const createStructuredAppSelector = createStructuredSelector.withTypes() @@ -50,12 +50,12 @@ describe('createStructuredSelector.withTypes()', () => { const structuredAppSelector = createStructuredAppSelector({ todos: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, alerts: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.alerts } @@ -67,13 +67,11 @@ describe('createStructuredSelector.withTypes()', () => { expectTypeOf(alerts).toEqualTypeOf() - expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf( + weakMapMemoize + ) - expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf(weakMapMemoize) expectTypeOf(structuredAppSelector.clearCache).returns.toBeVoid() @@ -99,30 +97,25 @@ describe('createStructuredSelector.withTypes()', () => { () => void >() - expectTypeOf( - structuredAppSelector.lastResult - ).returns.toEqualTypeOf(rootState) + expectTypeOf(structuredAppSelector.lastResult).returns.toEqualTypeOf( + rootState + ) expectTypeOf( structuredAppSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[]]>([ - rootState.todos, - rootState.alerts - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[]]>() expectTypeOf( structuredAppSelector.memoizedResultFunc - ).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + ).returns.toEqualTypeOf(structuredAppSelector.lastResult()) expectTypeOf(structuredAppSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf( + structuredAppSelector.lastResult() + ) }) test('should correctly infer memoize and argsMemoize', () => { @@ -139,13 +132,9 @@ describe('createStructuredSelector.withTypes()', () => { createSelectorLru ) - expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf< - typeof microMemoize - >(microMemoize) + expectTypeOf(structuredSelector.argsMemoize).toEqualTypeOf(microMemoize) - expectTypeOf(structuredSelector.memoize).toEqualTypeOf( - lruMemoize - ) + expectTypeOf(structuredSelector.memoize).toEqualTypeOf(lruMemoize) const { todos, alerts } = structuredSelector(rootState) @@ -171,44 +160,39 @@ describe('createStructuredSelector.withTypes()', () => { () => void >() - expectTypeOf( - structuredSelector.lastResult - ).returns.toEqualTypeOf(rootState) + expectTypeOf(structuredSelector.lastResult).returns.toEqualTypeOf(rootState) expectTypeOf( structuredSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[]]>([ - rootState.todos, - rootState.alerts - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[]]>() - expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.memoizedResultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) expectTypeOf(structuredSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredSelector.lastResult()) + expectTypeOf(structuredSelector.resultFunc).returns.toEqualTypeOf( + structuredSelector.lastResult() + ) }) test('supports additional parameters', () => { const structuredAppSelector = createStructuredAppSelector({ todos: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, alerts: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.alerts }, todoById: (state, id: number) => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos[id] } @@ -222,13 +206,11 @@ describe('createStructuredSelector.withTypes()', () => { expectTypeOf(todoById).toEqualTypeOf() - expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf( + weakMapMemoize + ) - expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf(weakMapMemoize) expectTypeOf(structuredAppSelector.clearCache).returns.toBeVoid() @@ -236,7 +218,7 @@ describe('createStructuredSelector.withTypes()', () => { [] >() - expectTypeOf(structuredAppSelector.dependencies).items.toMatchTypeOf< + expectTypeOf(structuredAppSelector.dependencies).items.toExtend< Selector >() @@ -269,29 +251,23 @@ describe('createStructuredSelector.withTypes()', () => { expectTypeOf( structuredAppSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[], Todo]>([ - rootState.todos, - rootState.alerts, - rootState.todos[0] - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[], Todo]>() expectTypeOf(structuredAppSelector.resultFunc).parameters.toEqualTypeOf< [Todo[], Alert[], Todo] - >([rootState.todos, rootState.alerts, rootState.todos[0]]) + >() expectTypeOf( structuredAppSelector.memoizedResultFunc - ).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + ).returns.toEqualTypeOf(structuredAppSelector.lastResult()) expectTypeOf(structuredAppSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf( + structuredAppSelector.lastResult() + ) }) // TODO: Remove this test block once `TypedStructuredSelectorCreator` is removed. @@ -301,12 +277,12 @@ describe('createStructuredSelector.withTypes()', () => { const structuredAppSelector = createStructuredAppSelector({ todos: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, alerts: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.alerts } @@ -318,13 +294,11 @@ describe('createStructuredSelector.withTypes()', () => { expectTypeOf(alerts).toEqualTypeOf() - expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf( + weakMapMemoize + ) - expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf(weakMapMemoize) expectTypeOf(structuredAppSelector.clearCache).returns.toBeVoid() @@ -350,42 +324,37 @@ describe('createStructuredSelector.withTypes()', () => { () => void >() - expectTypeOf( - structuredAppSelector.lastResult - ).returns.toEqualTypeOf(rootState) + expectTypeOf(structuredAppSelector.lastResult).returns.toEqualTypeOf( + rootState + ) expectTypeOf( structuredAppSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[]]>([ - rootState.todos, - rootState.alerts - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[]]>() expectTypeOf( structuredAppSelector.memoizedResultFunc - ).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + ).returns.toEqualTypeOf(structuredAppSelector.lastResult()) expectTypeOf(structuredAppSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf( + structuredAppSelector.lastResult() + ) }) test('should work with createSelector.withTypes()', () => { const structuredAppSelector = createStructuredAppSelector( { todos: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, alerts: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.alerts } @@ -399,13 +368,11 @@ describe('createStructuredSelector.withTypes()', () => { expectTypeOf(alerts).toEqualTypeOf() - expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf( + weakMapMemoize + ) - expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf(weakMapMemoize) expectTypeOf(structuredAppSelector.clearCache).returns.toBeVoid() @@ -431,30 +398,25 @@ describe('createStructuredSelector.withTypes()', () => { () => void >() - expectTypeOf( - structuredAppSelector.lastResult - ).returns.toEqualTypeOf(rootState) + expectTypeOf(structuredAppSelector.lastResult).returns.toEqualTypeOf( + rootState + ) expectTypeOf( structuredAppSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[]]>([ - rootState.todos, - rootState.alerts - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[]]>() expectTypeOf( structuredAppSelector.memoizedResultFunc - ).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + ).returns.toEqualTypeOf(structuredAppSelector.lastResult()) expectTypeOf(structuredAppSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf( + structuredAppSelector.lastResult() + ) }) test('StructuredSelectorCreator should lock down the state type', () => { @@ -464,12 +426,12 @@ describe('createStructuredSelector.withTypes()', () => { const structuredAppSelector = createStructuredAppSelector( { todos: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, alerts: state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.alerts } @@ -483,13 +445,11 @@ describe('createStructuredSelector.withTypes()', () => { expectTypeOf(alerts).toEqualTypeOf() - expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.argsMemoize).toEqualTypeOf( + weakMapMemoize + ) - expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf< - typeof weakMapMemoize - >(weakMapMemoize) + expectTypeOf(structuredAppSelector.memoize).toEqualTypeOf(weakMapMemoize) expectTypeOf(structuredAppSelector.clearCache).returns.toBeVoid() @@ -515,29 +475,24 @@ describe('createStructuredSelector.withTypes()', () => { () => void >() - expectTypeOf( - structuredAppSelector.lastResult - ).returns.toEqualTypeOf(rootState) + expectTypeOf(structuredAppSelector.lastResult).returns.toEqualTypeOf( + rootState + ) expectTypeOf( structuredAppSelector.memoizedResultFunc - ).parameters.toEqualTypeOf<[Todo[], Alert[]]>([ - rootState.todos, - rootState.alerts - ]) + ).parameters.toEqualTypeOf<[Todo[], Alert[]]>() expectTypeOf( structuredAppSelector.memoizedResultFunc - ).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + ).returns.toEqualTypeOf(structuredAppSelector.lastResult()) expectTypeOf(structuredAppSelector.memoizedResultFunc).toHaveProperty( 'clearCache' ) - expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf< - ReturnType - >(structuredAppSelector.lastResult()) + expectTypeOf(structuredAppSelector.resultFunc).returns.toEqualTypeOf( + structuredAppSelector.lastResult() + ) }) }) diff --git a/type-tests/deepNesting.test-d.ts b/type-tests/deepNesting.test-d.ts index c4bdc2411..b4c92d779 100644 --- a/type-tests/deepNesting.test-d.ts +++ b/type-tests/deepNesting.test-d.ts @@ -1,3 +1,5 @@ +import type { AnyFunction } from '@internal/types' +import type { Cache } from 'micro-memoize' import microMemoize from 'micro-memoize' import { createSelector, lruMemoize } from 'reselect' import { describe, test } from 'vitest' @@ -16,12 +18,13 @@ const state: RootState = { ] } -describe('deep nesting', () => { - test('Deep Nesting First And Second createSelector Overload', () => { - type State = { foo: string } - const readOne = (state: State) => state.foo +describe('type tests', () => { + test('issue #525: verify more than 12 selectors are accepted', () => { + // https://github.com/reduxjs/reselect/issues/525 - const selector0 = createSelector(readOne, one => one) + const selectTodos = (state: RootState) => state.todos + + const selector0 = createSelector(selectTodos, todos => todos) const selector1 = createSelector(selector0, s => s) const selector2 = createSelector(selector1, s => s) const selector3 = createSelector(selector2, s => s) @@ -34,9 +37,15 @@ describe('deep nesting', () => { const selector10 = createSelector(selector9, s => s, { memoize: microMemoize }) - selector10.dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + + expectTypeOf(selector10).toBeCallableWith(state) + + expectTypeOf( + selector10.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() + const selector11 = createSelector(selector10, s => s) const selector12 = createSelector(selector11, s => s) const selector13 = createSelector(selector12, s => s) @@ -47,9 +56,15 @@ describe('deep nesting', () => { const selector18 = createSelector(selector17, s => s) const selector19 = createSelector(selector18, s => s) const selector20 = createSelector(selector19, s => s) - selector20.dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].memoizedResultFunc.cache + + expectTypeOf(selector20).toBeCallableWith(state) + + expectTypeOf( + selector20.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.cache + ).toEqualTypeOf>() + const selector21 = createSelector(selector20, s => s) const selector22 = createSelector(selector21, s => s) const selector23 = createSelector(selector22, s => s) @@ -60,20 +75,25 @@ describe('deep nesting', () => { const selector28 = createSelector(selector27, s => s) const selector29 = createSelector(selector28, s => s) const selector30 = createSelector(selector29, s => s) - selector30.dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + + expectTypeOf(selector30).toBeCallableWith(state) + + expectTypeOf( + selector30.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() }) + test('Deep Nesting Second createSelector Overload', () => { - type State = { foo: string } - const readOne = (state: State) => state.foo + const selectTodos = (state: RootState) => state.todos - const selector0 = createSelector(readOne, one => one) + const selector0 = createSelector(selectTodos, todos => todos) const selector1 = createSelector(selector0, s => s, { memoize: lruMemoize }) @@ -104,6 +124,15 @@ describe('deep nesting', () => { const selector10 = createSelector(selector9, s => s, { memoize: lruMemoize }) + + expectTypeOf(selector10).toBeCallableWith(state) + + expectTypeOf( + selector10.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() + const selector11 = createSelector(selector10, s => s, { memoize: lruMemoize }) @@ -134,6 +163,15 @@ describe('deep nesting', () => { const selector20 = createSelector(selector19, s => s, { memoize: lruMemoize }) + + expectTypeOf(selector20).toBeCallableWith(state) + + expectTypeOf( + selector20.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() + const selector21 = createSelector(selector20, s => s, { memoize: lruMemoize }) @@ -161,13 +199,28 @@ describe('deep nesting', () => { const selector29 = createSelector(selector28, s => s, { memoize: lruMemoize }) + const selector30 = createSelector(selector29, s => s, { + memoize: lruMemoize + }) + + expectTypeOf(selector30).toBeCallableWith(state) + + expectTypeOf( + selector30.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() }) test('Deep Nesting Third createSelector Overload', () => { - type State = { foo: string } - const readOne = (state: State) => state.foo + const selectTodos = (state: RootState) => state.todos - const selector0 = createSelector(readOne, one => one) + const selector0 = createSelector(selectTodos, todos => todos) const selector1 = createSelector([selector0], s => s) const selector2 = createSelector([selector1], s => s) const selector3 = createSelector([selector2], s => s) @@ -178,6 +231,15 @@ describe('deep nesting', () => { const selector8 = createSelector([selector7], s => s) const selector9 = createSelector([selector8], s => s) const selector10 = createSelector([selector9], s => s) + + expectTypeOf(selector10).toBeCallableWith(state) + + expectTypeOf( + selector10.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() + const selector11 = createSelector([selector10], s => s) const selector12 = createSelector([selector11], s => s) const selector13 = createSelector([selector12], s => s) @@ -188,6 +250,15 @@ describe('deep nesting', () => { const selector18 = createSelector([selector17], s => s) const selector19 = createSelector([selector18], s => s) const selector20 = createSelector([selector19], s => s) + + expectTypeOf(selector20).toBeCallableWith(state) + + expectTypeOf( + selector20.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() + const selector21 = createSelector([selector20], s => s) const selector22 = createSelector([selector21], s => s) const selector23 = createSelector([selector22], s => s) @@ -198,6 +269,19 @@ describe('deep nesting', () => { const selector28 = createSelector([selector27], s => s) const selector29 = createSelector([selector28], s => s) const selector30 = createSelector([selector29], s => s) + + expectTypeOf(selector30).toBeCallableWith(state) + + expectTypeOf( + selector30.dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].dependencies[0].dependencies[0] + .dependencies[0].dependencies[0].memoizedResultFunc.clearCache + ).toEqualTypeOf<() => void>() }) test('createSelector Parameter Limit', () => { @@ -317,4 +401,34 @@ describe('deep nesting', () => { } ) }) + + test('nested selector', () => { + interface State { + foo: string + bar: number + baz: boolean + } + + const selector = createSelector( + createSelector( + (state: State) => state.foo, + (state: State) => state.bar, + (foo, bar) => ({ foo, bar }) + ), + (state: State) => state.baz, + ({ foo, bar }, baz) => { + const foo1: string = foo + // @ts-expect-error + const foo2: number = foo + + const bar1: number = bar + // @ts-expect-error + const bar2: string = bar + + const baz1: boolean = baz + // @ts-expect-error + const baz2: string = baz + } + ) + }) }) diff --git a/type-tests/lruMemoize.test-d.ts b/type-tests/lruMemoize.test-d.ts new file mode 100644 index 000000000..f1543941b --- /dev/null +++ b/type-tests/lruMemoize.test-d.ts @@ -0,0 +1,93 @@ +import type { AnyFunction } from '@internal/types' +import { groupBy, isEqual } from 'lodash' +import { + createSelectorCreator, + lruMemoize, + referenceEqualityCheck +} from 'reselect' + +describe('type tests', () => { + test('lruMemoize', () => { + const func = (a: string) => +a + + const memoized = lruMemoize(func) + + expectTypeOf(memoized('42')).toBeNumber() + + expectTypeOf(memoized('42')).not.toBeString() + + const memoized2 = lruMemoize( + (str: string, arr: string[]): { str: string; arr: string[] } => ({ + str, + arr + }), + (a: T, b: T) => { + return `${a}` === `${b}` + } + ) + + const ret2 = memoized2('', ['1', '2']) + + expectTypeOf(ret2.str).toBeString() + + expectTypeOf(ret2.arr).items.toBeString() + }) + + test('issue #384', () => { + // https://github.com/reduxjs/reselect/issues/384 + + function multiArgMemoize( + func: F, + a: number, + b: string, + equalityCheck = referenceEqualityCheck + ): F { + return func + } + + interface Transaction { + transactionId: string + } + + const toId = (transaction: Transaction) => transaction.transactionId + + const transactionsIds = (transactions: Transaction[]) => + transactions.map(toId) + + const collectionsEqual = (ts1: Transaction[], ts2: Transaction[]) => + isEqual(transactionsIds(ts1), transactionsIds(ts2)) + + expectTypeOf(createSelectorCreator).toBeCallableWith( + lruMemoize, + collectionsEqual + ) + + const createMultiMemoizeArgSelector = createSelectorCreator( + multiArgMemoize, + 42, + 'abcd', + referenceEqualityCheck + ) + + const select = createMultiMemoizeArgSelector( + (state: { foo: string }) => state.foo, + foo => `${foo}!` + ) + + // error is not applicable anymore + expectTypeOf(select.clearCache).toBeFunction() + + const createMultiMemoizeArgSelector2 = createSelectorCreator( + multiArgMemoize, + 42, + // @ts-expect-error + referenceEqualityCheck + ) + + expectTypeOf(lruMemoize).toBeCallableWith( + (transactions: Transaction[]) => + groupBy(transactions, item => item.transactionId), + collectionsEqual + ) + }) +}) diff --git a/type-tests/tsconfig.json b/type-tests/tsconfig.json deleted file mode 100644 index 0cf05eb4d..000000000 --- a/type-tests/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "esModuleInterop": true, - "strict": true, - "target": "ES2015", - "lib": ["ES2021.WeakRef"], - "declaration": true, - "noEmit": true, - "skipLibCheck": true, - "paths": { - "reselect": ["../src/index"], // @remap-prod-remove-line - "@internal/*": ["../src/*"] - } - }, - "include": ["**/*.ts", "../typescript_test/**/*.ts"] -} diff --git a/typescript_test/argsMemoize.typetest.ts b/typescript_test/argsMemoize.typetest.ts deleted file mode 100644 index 9729062c6..000000000 --- a/typescript_test/argsMemoize.typetest.ts +++ /dev/null @@ -1,1160 +0,0 @@ -import memoizeOne from 'memoize-one' -import microMemoize from 'micro-memoize' -import { - unstable_autotrackMemoize as autotrackMemoize, - createSelector, - createSelectorCreator, - lruMemoize, - weakMapMemoize -} from 'reselect' -import { expectExactType } from './typesTestUtils' - -interface RootState { - todos: { - id: number - completed: boolean - }[] -} -const state: RootState = { - todos: [ - { id: 0, completed: false }, - { id: 1, completed: false } - ] -} - -function overrideOnlyMemoizeInCreateSelector() { - const selectorDefaultSeparateInlineArgs = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: lruMemoize } - ) - const selectorDefaultArgsAsArray = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { memoize: lruMemoize } - ) - const selectorDefaultArgsAsArrayWithMemoizeOptions = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { memoize: lruMemoize, memoizeOptions: { maxSize: 2 } } - ) - const selectorDefaultSeparateInlineArgsWithMemoizeOptions = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: lruMemoize, memoizeOptions: { maxSize: 2 } } - ) - const selectorAutotrackSeparateInlineArgs = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: autotrackMemoize } - ) - const selectorAutotrackArgsAsArray = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { memoize: autotrackMemoize } - ) - // @ts-expect-error When memoize is autotrackMemoize, type of memoizeOptions needs to be the same as options args in autotrackMemoize. - const selectorAutotrackArgsAsArrayWithMemoizeOptions = createSelector( - [(state: RootState) => state.todos], - // @ts-expect-error - todos => todos.map(t => t.id), - { memoize: autotrackMemoize, memoizeOptions: { maxSize: 2 } } - ) - // @ts-expect-error When memoize is autotrackMemoize, type of memoizeOptions needs to be the same as options args in autotrackMemoize. - const selectorAutotrackSeparateInlineArgsWithMemoizeOptions = createSelector( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { memoize: autotrackMemoize, memoizeOptions: { maxSize: 2 } } - ) - const selectorWeakMapSeparateInlineArgs = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: weakMapMemoize } - ) - const selectorWeakMapArgsAsArray = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { memoize: weakMapMemoize } - ) - // @ts-expect-error When memoize is weakMapMemoize, type of memoizeOptions needs to be the same as options args in weakMapMemoize. - const selectorWeakMapArgsAsArrayWithMemoizeOptions = createSelector( - [(state: RootState) => state.todos], - // @ts-expect-error - todos => todos.map(t => t.id), - { memoize: weakMapMemoize, memoizeOptions: { maxSize: 2 } } - ) - // @ts-expect-error When memoize is weakMapMemoize, type of memoizeOptions needs to be the same as options args in weakMapMemoize. - const selectorWeakMapSeparateInlineArgsWithMemoizeOptions = createSelector( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { memoize: weakMapMemoize, memoizeOptions: { maxSize: 2 } } - ) - const createSelectorDefault = createSelectorCreator(lruMemoize) - const createSelectorWeakMap = createSelectorCreator(weakMapMemoize) - const createSelectorAutotrack = createSelectorCreator(autotrackMemoize) - const changeMemoizeMethodSelectorDefault = createSelectorDefault( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: weakMapMemoize } - ) - const changeMemoizeMethodSelectorWeakMap = createSelectorWeakMap( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: lruMemoize } - ) - const changeMemoizeMethodSelectorAutotrack = createSelectorAutotrack( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: lruMemoize } - ) - const changeMemoizeMethodSelectorDefaultWithMemoizeOptions = - // @ts-expect-error When memoize is changed to weakMapMemoize or autotrackMemoize, memoizeOptions cannot be the same type as options args in lruMemoize. - createSelectorDefault( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { memoize: weakMapMemoize, memoizeOptions: { maxSize: 2 } } - ) - const changeMemoizeMethodSelectorWeakMapWithMemoizeOptions = - createSelectorWeakMap( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: lruMemoize, memoizeOptions: { maxSize: 2 } } // When memoize is changed to lruMemoize, memoizeOptions can now be the same type as options args in lruMemoize. - ) - const changeMemoizeMethodSelectorAutotrackWithMemoizeOptions = - createSelectorAutotrack( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { memoize: lruMemoize, memoizeOptions: { maxSize: 2 } } // When memoize is changed to lruMemoize, memoizeOptions can now be the same type as options args in lruMemoize. - ) -} - -function overrideOnlyArgsMemoizeInCreateSelector() { - const selectorDefaultSeparateInlineArgs = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize } - ) - const selectorDefaultArgsAsArray = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize } - ) - const selectorDefaultArgsAsArrayWithMemoizeOptions = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize, argsMemoizeOptions: { maxSize: 2 } } - ) - const selectorDefaultSeparateInlineArgsWithMemoizeOptions = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize, argsMemoizeOptions: { maxSize: 2 } } - ) - const selectorAutotrackSeparateInlineArgs = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: autotrackMemoize } - ) - const selectorAutotrackArgsAsArray = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { argsMemoize: autotrackMemoize } - ) - // @ts-expect-error When argsMemoize is autotrackMemoize, type of argsMemoizeOptions needs to be the same as options args in autotrackMemoize. - const selectorAutotrackArgsAsArrayWithMemoizeOptions = createSelector( - [(state: RootState) => state.todos], - // @ts-expect-error - todos => todos.map(t => t.id), - { - argsMemoize: autotrackMemoize, - argsMemoizeOptions: { maxSize: 2 } - } - ) - // @ts-expect-error When argsMemoize is autotrackMemoize, type of argsMemoizeOptions needs to be the same as options args in autotrackMemoize. - const selectorAutotrackSeparateInlineArgsWithMemoizeOptions = createSelector( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { - argsMemoize: autotrackMemoize, - argsMemoizeOptions: { maxSize: 2 } - } - ) - const selectorWeakMapSeparateInlineArgs = createSelector( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: weakMapMemoize } - ) - const selectorWeakMapArgsAsArray = createSelector( - [(state: RootState) => state.todos], - todos => todos.map(t => t.id), - { argsMemoize: weakMapMemoize } - ) - // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. - const selectorWeakMapArgsAsArrayWithMemoizeOptions = createSelector( - [(state: RootState) => state.todos], - // @ts-expect-error - todos => todos.map(t => t.id), - { argsMemoize: weakMapMemoize, argsMemoizeOptions: { maxSize: 2 } } - ) - // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. - const selectorWeakMapSeparateInlineArgsWithMemoizeOptions = createSelector( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { argsMemoize: weakMapMemoize, argsMemoizeOptions: { maxSize: 2 } } - ) - // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. - const selectorWeakMapSeparateInlineArgsWithMemoizeOptions1 = createSelector( - [ - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id) - ], - { - argsMemoize: weakMapMemoize, - argsMemoizeOptions: { maxSize: 2 } - } - ) - // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. - const selectorWeakMapSeparateInlineArgsWithMemoizeOptions2 = createSelector( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { - memoize: lruMemoize, - argsMemoize: weakMapMemoize, - memoizeOptions: { - equalityCheck: - // @ts-expect-error - (a, b) => a === b, - maxSize: 2 - }, - argsMemoizeOptions: { maxSize: 2 } - } - ) - - const createSelectorLruMemoize = createSelectorCreator({ - memoize: lruMemoize - }) - const selectorWeakMapSeparateInlineArgsWithMemoizeOptions3 = - // @ts-expect-error When argsMemoize is weakMapMemoize, type of argsMemoizeOptions needs to be the same as options args in weakMapMemoize. - createSelectorLruMemoize( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { - memoize: lruMemoize, - argsMemoize: weakMapMemoize, - // memoizeOptions: [], - memoizeOptions: [ - { - equalityCheck: - // @ts-expect-error - (a, b) => a === b, - maxSize: 2 - } - ], - argsMemoizeOptions: [{ maxSize: 2 }] - } - ) - - const selectorWeakMapSeparateInlineArgsWithMemoizeOptions5 = - // @ts-expect-error - createSelectorLruMemoize( - [(state: RootState) => state.todos], - // @ts-expect-error - todos => todos.map(t => t.id), - { - argsMemoize: weakMapMemoize, - memoizeOptions: [{ isPromise: false }], - argsMemoizeOptions: [] - } - ) - const selectorWeakMapSeparateInlineArgsWithMemoizeOptions6 = - createSelectorLruMemoize( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { - argsMemoize: weakMapMemoize, - memoize: weakMapMemoize, - memoizeOptions: [], - argsMemoizeOptions: [] - // argsMemoizeOptions: (a, b) => a === b - } - ) - const createSelectorDefault = createSelectorCreator(lruMemoize) - const createSelectorWeakMap = createSelectorCreator(weakMapMemoize) - const createSelectorAutotrack = createSelectorCreator(autotrackMemoize) - const changeMemoizeMethodSelectorDefault = createSelectorDefault( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: weakMapMemoize } - ) - const changeMemoizeMethodSelectorWeakMap = createSelectorWeakMap( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize } - ) - const changeMemoizeMethodSelectorAutotrack = createSelectorAutotrack( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize } - ) - const changeMemoizeMethodSelectorDefaultWithMemoizeOptions = - // @ts-expect-error When argsMemoize is changed to weakMapMemoize or autotrackMemoize, argsMemoizeOptions cannot be the same type as options args in lruMemoize. - createSelectorDefault( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { argsMemoize: weakMapMemoize, argsMemoizeOptions: { maxSize: 2 } } - ) - const changeMemoizeMethodSelectorWeakMapWithMemoizeOptions = - createSelectorWeakMap( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize, argsMemoizeOptions: { maxSize: 2 } } // When argsMemoize is changed to lruMemoize, argsMemoizeOptions can now be the same type as options args in lruMemoize. - ) - const changeMemoizeMethodSelectorAutotrackWithMemoizeOptions = - createSelectorAutotrack( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { argsMemoize: lruMemoize, argsMemoizeOptions: { maxSize: 2 } } // When argsMemoize is changed to lruMemoize, argsMemoizeOptions can now be the same type as options args in lruMemoize. - ) -} - -function overrideMemoizeAndArgsMemoizeInCreateSelector() { - const createSelectorMicroMemoize = createSelectorCreator({ - memoize: microMemoize, - memoizeOptions: [{ isEqual: (a, b) => a === b }], - // memoizeOptions: { isEqual: (a, b) => a === b }, - argsMemoize: microMemoize, - argsMemoizeOptions: { isEqual: (a, b) => a === b } - }) - const selectorMicroMemoize = createSelectorMicroMemoize( - (state: RootState) => state.todos, - todos => todos.map(({ id }) => id) - ) - expectExactType(selectorMicroMemoize(state)) - // @ts-expect-error - selectorMicroMemoize() - // Checking existence of fields related to `argsMemoize` - selectorMicroMemoize.cache - selectorMicroMemoize.fn() - selectorMicroMemoize.isMemoized - selectorMicroMemoize.options - // @ts-expect-error - selectorMicroMemoize.clearCache() - // Checking existence of fields related to `memoize` - selectorMicroMemoize.memoizedResultFunc.cache - selectorMicroMemoize.memoizedResultFunc.fn() - selectorMicroMemoize.memoizedResultFunc.isMemoized - selectorMicroMemoize.memoizedResultFunc.options - // @ts-expect-error - selectorMicroMemoize.memoizedResultFunc.clearCache() - // Checking existence of fields related to the actual memoized selector - selectorMicroMemoize.dependencies - expectExactType< - [ - (state: RootState) => { - id: number - completed: boolean - }[] - ] - >(selectorMicroMemoize.dependencies) - expectExactType(selectorMicroMemoize.lastResult()) - // @ts-expect-error - selectorMicroMemoize.memoizedResultFunc() - expectExactType( - selectorMicroMemoize.memoizedResultFunc([{ id: 0, completed: true }]) - ) - selectorMicroMemoize.recomputations() - selectorMicroMemoize.resetRecomputations() - // @ts-expect-error - selectorMicroMemoize.resultFunc() - expectExactType( - selectorMicroMemoize.resultFunc([{ id: 0, completed: true }]) - ) - - // Checking to see if types dynamically change if memoize or argsMemoize are overridden inside `createSelector`. - // `microMemoize` was initially passed into `createSelectorCreator` - // as `memoize` and `argsMemoize`, After overriding them both to `lruMemoize`, - // not only does the type for `memoizeOptions` and `argsMemoizeOptions` change to - // the options parameter of `lruMemoize`, the output selector fields - // also change their type to the return type of `lruMemoize`. - const selectorMicroMemoizeOverridden = createSelectorMicroMemoize( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { - memoize: lruMemoize, - argsMemoize: lruMemoize, - memoizeOptions: { equalityCheck: (a, b) => a === b, maxSize: 2 }, - argsMemoizeOptions: { equalityCheck: (a, b) => a === b, maxSize: 3 } - } - ) - expectExactType(selectorMicroMemoizeOverridden(state)) - // @ts-expect-error - selectorMicroMemoizeOverridden() - // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverridden.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.options - // Checking existence of fields related to `memoize` - selectorMicroMemoizeOverridden.memoizedResultFunc.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverridden.memoizedResultFunc.options - // Checking existence of fields related to the actual memoized selector - expectExactType< - [ - (state: RootState) => { - id: number - completed: boolean - }[] - ] - >(selectorMicroMemoizeOverridden.dependencies) - expectExactType( - selectorMicroMemoizeOverridden.memoizedResultFunc([ - { id: 0, completed: true } - ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverridden.memoizedResultFunc() - selectorMicroMemoizeOverridden.recomputations() - selectorMicroMemoizeOverridden.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverridden.resultFunc() - expectExactType( - selectorMicroMemoizeOverridden.resultFunc([{ id: 0, completed: true }]) - ) - // Making sure the type behavior is consistent when args are passed in as an array. - const selectorMicroMemoizeOverriddenArray = createSelectorMicroMemoize( - [(state: RootState) => state.todos], - todos => todos.map(({ id }) => id), - { - memoize: lruMemoize, - argsMemoize: lruMemoize, - memoizeOptions: { equalityCheck: (a, b) => a === b, maxSize: 2 }, - argsMemoizeOptions: { equalityCheck: (a, b) => a === b, maxSize: 3 } - } - ) - expectExactType(selectorMicroMemoizeOverriddenArray(state)) - // @ts-expect-error - selectorMicroMemoizeOverriddenArray() - // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverriddenArray.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.options - // Checking existence of fields related to `memoize` - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverriddenArray.memoizedResultFunc.options - // Checking existence of fields related to the actual memoized selector - expectExactType< - [ - (state: RootState) => { - id: number - completed: boolean - }[] - ] - >(selectorMicroMemoizeOverriddenArray.dependencies) - expectExactType( - selectorMicroMemoizeOverriddenArray.memoizedResultFunc([ - { id: 0, completed: true } - ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverriddenArray.memoizedResultFunc() - selectorMicroMemoizeOverriddenArray.recomputations() - selectorMicroMemoizeOverriddenArray.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverriddenArray.resultFunc() - expectExactType( - selectorMicroMemoizeOverriddenArray.resultFunc([{ id: 0, completed: true }]) - ) - const selectorMicroMemoizeOverrideArgsMemoizeOnlyWrong = - // @ts-expect-error Because `memoizeOptions` should not contain `resultEqualityCheck`. - createSelectorMicroMemoize( - (state: RootState) => state.todos, - todos => todos.map(({ id }) => id), - { - argsMemoize: lruMemoize, - memoizeOptions: { - isPromise: false, - resultEqualityCheck: - // @ts-expect-error - (a, b) => a === b - }, - argsMemoizeOptions: { resultEqualityCheck: (a, b) => a === b } - } - ) - const selectorMicroMemoizeOverrideArgsMemoizeOnly = - createSelectorMicroMemoize( - (state: RootState) => state.todos, - todos => todos.map(({ id }) => id), - { - argsMemoize: lruMemoize, - memoizeOptions: { isPromise: false }, - argsMemoizeOptions: { resultEqualityCheck: (a, b) => a === b } - } - ) - expectExactType(selectorMicroMemoizeOverrideArgsMemoizeOnly(state)) - // @ts-expect-error - selectorMicroMemoizeOverrideArgsMemoizeOnly() - // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverrideArgsMemoizeOnly.clearCache() // Prior to override, this field did NOT exist. - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideArgsMemoizeOnly.options - - // Checking existence of fields related to `memoize`, these should still be the same. - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.cache - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.fn() - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.isMemoized - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.options - // @ts-expect-error Note that since we did not override `memoize` in the options object, - // `memoizedResultFunc.clearCache` is still an invalid field access. - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.clearCache() - // Checking existence of fields related to the actual memoized selector - expectExactType< - [ - (state: RootState) => { - id: number - completed: boolean - }[] - ] - >(selectorMicroMemoizeOverrideArgsMemoizeOnly.dependencies) - expectExactType( - selectorMicroMemoizeOverrideArgsMemoizeOnly.lastResult() - ) - expectExactType( - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc([ - { id: 0, completed: true } - ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc() - selectorMicroMemoizeOverrideArgsMemoizeOnly.recomputations() - selectorMicroMemoizeOverrideArgsMemoizeOnly.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverrideArgsMemoizeOnly.resultFunc() - expectExactType( - selectorMicroMemoizeOverrideArgsMemoizeOnly.resultFunc([ - { id: 0, completed: true } - ]) - ) - - const selectorMicroMemoizeOverrideMemoizeOnly = createSelectorMicroMemoize( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { - memoize: lruMemoize, - memoizeOptions: { resultEqualityCheck: (a, b) => a === b } - } - ) - expectExactType(selectorMicroMemoizeOverrideMemoizeOnly(state)) - // @ts-expect-error - selectorMicroMemoizeOverrideMemoizeOnly() - - // Checking existence of fields related to `argsMemoize` - selectorMicroMemoizeOverrideMemoizeOnly.cache - selectorMicroMemoizeOverrideMemoizeOnly.fn - selectorMicroMemoizeOverrideMemoizeOnly.isMemoized - selectorMicroMemoizeOverrideMemoizeOnly.options - // @ts-expect-error Note that since we did not override `argsMemoize` in the options object, - // `selector.clearCache` is still an invalid field access. - selectorMicroMemoizeOverrideMemoizeOnly.clearCache() - - // Checking existence of fields related to `memoize` - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.cache - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.fn() - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.isMemoized - // @ts-expect-error Prior to override, this field DID exist. - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.options - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.clearCache() // Prior to override, this field did NOT exist. - - // Checking existence of fields related to the actual memoized selector - expectExactType< - [ - (state: RootState) => { - id: number - completed: boolean - }[] - ] - >(selectorMicroMemoizeOverrideMemoizeOnly.dependencies) - expectExactType( - selectorMicroMemoizeOverrideMemoizeOnly.lastResult() - ) - expectExactType( - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc([ - { id: 0, completed: true } - ]) - ) - // @ts-expect-error - selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc() - selectorMicroMemoizeOverrideMemoizeOnly.recomputations() - selectorMicroMemoizeOverrideMemoizeOnly.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeOverrideMemoizeOnly.resultFunc() - expectExactType( - selectorMicroMemoizeOverrideMemoizeOnly.resultFunc([ - { id: 0, completed: true } - ]) - ) - - const selectorMicroMemoizePartiallyOverridden = - // @ts-expect-error Since `argsMemoize` is set to `lruMemoize`, `argsMemoizeOptions` must match the options object parameter of `lruMemoize` - createSelectorMicroMemoize( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { - memoize: lruMemoize, - argsMemoize: lruMemoize, - memoizeOptions: { - equalityCheck: - // @ts-expect-error - (a, b) => a === b, - maxSize: 2 - }, - argsMemoizeOptions: { isPromise: false } // This field causes a type error since it does not match the options param of `lruMemoize`. - } - ) - const selectorMicroMemoizePartiallyOverridden1 = - // @ts-expect-error Since `argsMemoize` is set to `lruMemoize`, `argsMemoizeOptions` must match the options object parameter of `lruMemoize` - createSelectorMicroMemoize( - (state: RootState) => state.todos, - // @ts-expect-error - todos => todos.map(t => t.id), - { - memoize: lruMemoize, - argsMemoize: lruMemoize, - memoizeOptions: [ - { - equalityCheck: - // @ts-expect-error - (a, b) => a === b, - maxSize: 2 - } - ], - argsMemoizeOptions: [{ isPromise: false }] // This field causes a type error since it does not match the options param of `lruMemoize`. - } - ) - const selectorMicroMemoizePartiallyOverridden2 = createSelectorMicroMemoize( - (state: RootState) => state.todos, - todos => todos.map(t => t.id), - { - argsMemoizeOptions: [{ isPromise: false }] - } - ) - - const selectorDefaultParametric = createSelector( - (state: RootState, id: number) => id, - (state: RootState) => state.todos, - (id, todos) => todos.filter(todo => todo.id === id), - { - argsMemoize: microMemoize, - devModeChecks: { inputStabilityCheck: 'never' }, - memoize: memoizeOne, - argsMemoizeOptions: [], - memoizeOptions: [(a, b) => a === b] - } - ) - expectExactType< - { - id: number - completed: boolean - }[] - >(selectorDefaultParametric(state, 0)) - expectExactType< - { - id: number - completed: boolean - }[] - >(selectorDefaultParametric(state, 1)) - // @ts-expect-error - selectorDefaultParametric(state) - // @ts-expect-error - selectorDefaultParametric(1) - // @ts-expect-error - selectorDefaultParametric(state, '') - // @ts-expect-error - selectorDefaultParametric(state, 1, 1) - // Checking existence of fields related to `argsMemoize` - // Prior to override, this field did NOT exist. - selectorDefaultParametric.cache - // Prior to override, this field did NOT exist. - selectorDefaultParametric.fn - // Prior to override, this field did NOT exist. - selectorDefaultParametric.isMemoized - // Prior to override, this field did NOT exist. - selectorDefaultParametric.options - // @ts-expect-error Prior to override, this field DID exist. - selectorDefaultParametric.clearCache() - - // Checking existence of fields related to `memoize` - // @ts-expect-error Prior to override, this field DID exist. - selectorDefaultParametric.memoizedResultFunc.clearCache() - // Prior to override, this field did NOT exist. - selectorDefaultParametric.memoizedResultFunc.clear() - - // Checking existence of fields related to the actual memoized selector - expectExactType< - [ - (state: RootState, id: number) => number, - (state: RootState) => { id: number; completed: boolean }[] - ] - >(selectorDefaultParametric.dependencies) - expectExactType<{ id: number; completed: boolean }[]>( - selectorDefaultParametric.lastResult() - ) - expectExactType<{ id: number; completed: boolean }[]>( - selectorDefaultParametric.memoizedResultFunc(0, [ - { id: 0, completed: true } - ]) - ) - // @ts-expect-error - selectorDefaultParametric.memoizedResultFunc() - selectorDefaultParametric.recomputations() - selectorDefaultParametric.resetRecomputations() - // @ts-expect-error - selectorDefaultParametric.resultFunc() - expectExactType<{ id: number; completed: boolean }[]>( - selectorDefaultParametric.resultFunc(0, [{ id: 0, completed: true }]) - ) -} - -function memoizeAndArgsMemoizeInCreateSelectorCreator() { - // If we don't pass in `argsMemoize`, the type for `argsMemoizeOptions` - // falls back to the options parameter of `lruMemoize`. - const createSelectorArgsMemoizeOptionsFallbackToDefault = - createSelectorCreator({ - memoize: microMemoize, - memoizeOptions: [{ isPromise: false }], - argsMemoizeOptions: { resultEqualityCheck: (a, b) => a === b } - }) - const selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault = - createSelectorArgsMemoizeOptionsFallbackToDefault( - (state: RootState) => state.todos, - todos => todos.map(({ id }) => id) - ) - expectExactType( - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault(state) - ) - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.clearCache() - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.cache - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.fn - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.isMemoized - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.options - // Checking existence of fields related to `memoize` - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc - .cache - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc.fn() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc - .isMemoized - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc - .options - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc.clearCache() - // Checking existence of fields related to the actual memoized selector - expectExactType< - [ - (state: RootState) => { - id: number - completed: boolean - }[] - ] - >(selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.dependencies) - expectExactType( - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.lastResult() - ) - expectExactType( - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc([ - { id: 0, completed: true } - ]) - ) - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.recomputations() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resetRecomputations() - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc() - expectExactType( - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc([ - { id: 0, completed: true } - ]) - ) - expectExactType( - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoize - ) - expectExactType( - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.argsMemoize - ) - - const createSelectorWithWrongArgsMemoizeOptions = - // @ts-expect-error If we don't pass in `argsMemoize`, the type for `argsMemoizeOptions` falls back to the options parameter of `weakMapMemoize`. - createSelectorCreator({ - memoize: microMemoize, - memoizeOptions: { isEqual: (a, b) => a === b }, - argsMemoizeOptions: { - isEqual: - // @ts-expect-error implicit any - (a, b) => a === b - } - }) - - // When passing in an options object as the first argument, there should be no other arguments. - const createSelectorWrong = createSelectorCreator( - { - // @ts-expect-error - memoize: microMemoize, - // @ts-expect-error - memoizeOptions: { isEqual: (a, b) => a === b }, - // @ts-expect-error - argsMemoizeOptions: { equalityCheck: (a, b) => a === b } - }, - [] // This causes the error. - ) -} - -function deepNesting() { - type State = { foo: string } - const readOne = (state: State) => state.foo - - const selector0 = createSelector(readOne, one => one) - const selector1 = createSelector(selector0, s => s) - const selector2 = createSelector(selector1, s => s) - const selector3 = createSelector(selector2, s => s) - const selector4 = createSelector(selector3, s => s) - const selector5 = createSelector(selector4, s => s) - const selector6 = createSelector(selector5, s => s) - const selector7 = createSelector(selector6, s => s) - const selector8 = createSelector(selector7, s => s) - const selector9 = createSelector(selector8, s => s) - const selector10 = createSelector(selector9, s => s, { - memoize: microMemoize - }) - selector10.dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].memoizedResultFunc.clearCache - const selector11 = createSelector(selector10, s => s) - const selector12 = createSelector(selector11, s => s) - const selector13 = createSelector(selector12, s => s) - const selector14 = createSelector(selector13, s => s) - const selector15 = createSelector(selector14, s => s) - const selector16 = createSelector(selector15, s => s) - const selector17 = createSelector(selector16, s => s) - const selector18 = createSelector(selector17, s => s) - const selector19 = createSelector(selector18, s => s) - const selector20 = createSelector(selector19, s => s) - selector20.dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].memoizedResultFunc.cache - const selector21 = createSelector(selector20, s => s) - const selector22 = createSelector(selector21, s => s) - const selector23 = createSelector(selector22, s => s) - const selector24 = createSelector(selector23, s => s) - const selector25 = createSelector(selector24, s => s) - const selector26 = createSelector(selector25, s => s) - const selector27 = createSelector(selector26, s => s) - const selector28 = createSelector(selector27, s => s) - const selector29 = createSelector(selector28, s => s) - const selector30 = createSelector(selector29, s => s) - selector30.dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].dependencies[0].dependencies[0] - .dependencies[0].dependencies[0].memoizedResultFunc.clearCache -} - -function deepNesting1() { - type State = { foo: string } - const readOne = (state: State) => state.foo - - const selector0 = createSelector(readOne, one => one) - const selector1 = createSelector([selector0], s => s) - const selector2 = createSelector([selector1], s => s) - const selector3 = createSelector([selector2], s => s) - const selector4 = createSelector([selector3], s => s) - const selector5 = createSelector([selector4], s => s) - const selector6 = createSelector([selector5], s => s) - const selector7 = createSelector([selector6], s => s) - const selector8 = createSelector([selector7], s => s) - const selector9 = createSelector([selector8], s => s) - const selector10 = createSelector([selector9], s => s) - const selector11 = createSelector([selector10], s => s) - const selector12 = createSelector([selector11], s => s) - const selector13 = createSelector([selector12], s => s) - const selector14 = createSelector([selector13], s => s) - const selector15 = createSelector([selector14], s => s) - const selector16 = createSelector([selector15], s => s) - const selector17 = createSelector([selector16], s => s) - const selector18 = createSelector([selector17], s => s) - const selector19 = createSelector([selector18], s => s) - const selector20 = createSelector([selector19], s => s) - const selector21 = createSelector([selector20], s => s) - const selector22 = createSelector([selector21], s => s) - const selector23 = createSelector([selector22], s => s) - const selector24 = createSelector([selector23], s => s) - const selector25 = createSelector([selector24], s => s) - const selector26 = createSelector([selector25], s => s) - const selector27 = createSelector([selector26], s => s) - const selector28 = createSelector([selector27], s => s) - const selector29 = createSelector([selector28], s => s) - const selector30 = createSelector([selector29], s => s) -} - -function deepNesting2() { - type State = { foo: string } - const readOne = (state: State) => state.foo - - const selector0 = createSelector(readOne, one => one) - const selector1 = createSelector(selector0, s => s, { - memoize: lruMemoize - }) - const selector2 = createSelector(selector1, s => s, { - memoize: lruMemoize - }) - const selector3 = createSelector(selector2, s => s, { - memoize: lruMemoize - }) - const selector4 = createSelector(selector3, s => s, { - memoize: lruMemoize - }) - const selector5 = createSelector(selector4, s => s, { - memoize: lruMemoize - }) - const selector6 = createSelector(selector5, s => s, { - memoize: lruMemoize - }) - const selector7 = createSelector(selector6, s => s, { - memoize: lruMemoize - }) - const selector8 = createSelector(selector7, s => s, { - memoize: lruMemoize - }) - const selector9 = createSelector(selector8, s => s, { - memoize: lruMemoize - }) - const selector10 = createSelector(selector9, s => s, { - memoize: lruMemoize - }) - const selector11 = createSelector(selector10, s => s, { - memoize: lruMemoize - }) - const selector12 = createSelector(selector11, s => s, { - memoize: lruMemoize - }) - const selector13 = createSelector(selector12, s => s, { - memoize: lruMemoize - }) - const selector14 = createSelector(selector13, s => s, { - memoize: lruMemoize - }) - const selector15 = createSelector(selector14, s => s, { - memoize: lruMemoize - }) - const selector16 = createSelector(selector15, s => s, { - memoize: lruMemoize - }) - const selector17 = createSelector(selector16, s => s, { - memoize: lruMemoize - }) - const selector18 = createSelector(selector17, s => s, { - memoize: lruMemoize - }) - const selector19 = createSelector(selector18, s => s, { - memoize: lruMemoize - }) - const selector20 = createSelector(selector19, s => s, { - memoize: lruMemoize - }) - const selector21 = createSelector(selector20, s => s, { - memoize: lruMemoize - }) - const selector22 = createSelector(selector21, s => s, { - memoize: lruMemoize - }) - const selector23 = createSelector(selector22, s => s, { - memoize: lruMemoize - }) - const selector24 = createSelector(selector23, s => s, { - memoize: lruMemoize - }) - const selector25 = createSelector(selector24, s => s, { - memoize: lruMemoize - }) - const selector26 = createSelector(selector25, s => s, { - memoize: lruMemoize - }) - const selector27 = createSelector(selector26, s => s, { - memoize: lruMemoize - }) - const selector28 = createSelector(selector27, s => s, { - memoize: lruMemoize - }) - const selector29 = createSelector(selector28, s => s, { - memoize: lruMemoize - }) -} - -function parameterLimit() { - const selector = createSelector( - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testStringArray: string[] }) => state.testStringArray, - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testStringArray: string[] }) => state.testStringArray, - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testStringArray: string[] }) => state.testStringArray, - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testStringArray: string[] }) => state.testStringArray, - ( - foo1: string, - foo2: number, - foo3: boolean, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: number, - foo9: string[], - foo10: string, - foo11: number, - foo12: boolean, - foo13: string, - foo14: string, - foo15: string, - foo16: string, - foo17: number, - foo18: string[], - foo19: string, - foo20: number, - foo21: boolean, - foo22: string, - foo23: string, - foo24: string, - foo25: string, - foo26: number, - foo27: string[], - foo28: string, - foo29: number, - foo30: boolean, - foo31: string, - foo32: string, - foo33: string, - foo34: string, - foo35: number, - foo36: string[] - ) => { - return { - foo1, - foo2, - foo3, - foo4, - foo5, - foo6, - foo7, - foo8, - foo9, - foo10, - foo11, - foo12, - foo13, - foo14, - foo15, - foo16, - foo17, - foo18, - foo19, - foo20, - foo21, - foo22, - foo23, - foo24, - foo25, - foo26, - foo27, - foo28, - foo29, - foo30, - foo31, - foo32, - foo33, - foo34, - foo35, - foo36 - } - } - ) -} diff --git a/typescript_test/test.ts b/typescript_test/test.ts deleted file mode 100644 index 0795f2e70..000000000 --- a/typescript_test/test.ts +++ /dev/null @@ -1,1738 +0,0 @@ -/* eslint-disable no-use-before-define */ - -import { configureStore, createSlice } from '@reduxjs/toolkit' -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' -import { groupBy, isEqual } from 'lodash' -import memoizeOne from 'memoize-one' -import microMemoize from 'micro-memoize' -import type { TypedUseSelectorHook } from 'react-redux' -import { useSelector } from 'react-redux' -import type { - GetStateFromSelectors, - Selector, - SelectorResultArray, - TypedStructuredSelectorCreator -} from 'reselect' -import { - createSelector, - createSelectorCreator, - createStructuredSelector, - lruMemoize, - referenceEqualityCheck -} from 'reselect' -import { expectExactType } from './typesTestUtils' - -type Exact = (() => T extends A ? 1 : 0) extends () => T extends B - ? 1 - : 0 - ? A extends B - ? B extends A - ? unknown - : never - : never - : never - -interface StateA { - a: number -} - -interface StateAB { - a: number - b: number -} - -interface StateSub { - sub: { - a: number - } -} - -// Test exporting -export const testExportBasic = createSelector( - (state: StateA) => state.a, - a => a -) - -// Test for exporting declaration of created selector creator -export const testExportStructured = createSelectorCreator( - lruMemoize, - (a, b) => typeof a === typeof b -) - -function testSelector() { - type State = { foo: string } - - const selector = createSelector( - (state: State) => state.foo, - foo => foo - ) - - const res = selector.resultFunc('test') - selector.recomputations() - selector.resetRecomputations() - - const foo: string = selector({ foo: 'bar' }) - - // @ts-expect-error - selector({ foo: 'bar' }, { prop: 'value' }) - - // @ts-expect-error - const num: number = selector({ foo: 'bar' }) - - // allows heterogeneous parameter type input selectors - createSelector( - (state: { foo: string }) => state.foo, - (state: { bar: number }) => state.bar, - (foo, bar) => 1 - ) - - const selectorWithUnions = createSelector( - (state: State, val: string | number) => state.foo, - (state: State, val: string | number) => val, - (foo, val) => val - ) -} - -function testNestedSelector() { - type State = { foo: string; bar: number; baz: boolean } - - const selector = createSelector( - createSelector( - (state: State) => state.foo, - (state: State) => state.bar, - (foo, bar) => ({ foo, bar }) - ), - (state: State) => state.baz, - ({ foo, bar }, baz) => { - const foo1: string = foo - // @ts-expect-error - const foo2: number = foo - - const bar1: number = bar - // @ts-expect-error - const bar2: string = bar - - const baz1: boolean = baz - // @ts-expect-error - const baz2: string = baz - } - ) -} - -function testSelectorAsCombiner() { - type SubState = { foo: string } - type State = { bar: SubState } - - const subSelector = createSelector( - (state: SubState) => state.foo, - foo => foo - ) - - const selector = createSelector((state: State) => state.bar, subSelector) - - // @ts-expect-error - selector({ foo: '' }) - - // @ts-expect-error - const n: number = selector({ bar: { foo: '' } }) - - const s: string = selector({ bar: { foo: '' } }) -} - -type Component

= (props: P) => any - -declare function connect( - selector: Selector -): (component: Component

) => Component

- -function testConnect() { - connect( - createSelector( - (state: { foo: string }) => state.foo, - foo => ({ foo }) - ) - )(props => { - // @ts-expect-error - props.bar - - const foo: string = props.foo - }) - - const selector2 = createSelector( - (state: { foo: string }) => state.foo, - (state: { baz: number }, props: { bar: number }) => props.bar, - (foo, bar) => ({ foo, baz: bar }) - ) - - const connected = connect(selector2)(props => { - const foo: string = props.foo - const bar: number = props.bar - const baz: number = props.baz - // @ts-expect-error - props.fizz - }) - - connected({ bar: 42 }) - - // @ts-expect-error - connected({ bar: 42, baz: 123 }) -} - -function testInvalidTypeInCombinator() { - // @ts-expect-error - createSelector( - (state: { foo: string }) => state.foo, - (foo: number) => foo - ) - - createSelector( - (state: { foo: string; bar: number; baz: boolean }) => state.foo, - (state: any) => state.bar, - (state: any) => state.baz, - // @ts-expect-error - (foo: string, bar: number, baz: boolean, fizz: string) => {} - ) - - // does not allow heterogeneous parameter type - // selectors when the combinator function is typed differently - // @ts-expect-error - createSelector( - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testNumber: string }) => state.testNumber, - (state: { testStringArray: string[] }) => state.testStringArray, - ( - foo1: string, - foo2: number, - foo3: boolean, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: number, - foo9: string[] - ) => { - return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } - } - ) - - // does not allow a large array of heterogeneous parameter type - // selectors when the combinator function is typed differently - // @ts-expect-error - createSelector( - [ - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testNumber: string }) => state.testNumber, - (state: { testStringArray: string[] }) => state.testStringArray - ], - ( - foo1: string, - foo2: number, - foo3: boolean, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: number, - foo9: string[] - ) => { - return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } - } - ) -} - -function testParametricSelector() { - type State = { foo: string } - type Props = { bar: number } - - // allows heterogeneous parameter type selectors - const selector1 = createSelector( - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testStringArray: string[] }) => state.testStringArray, - ( - foo1: string, - foo2: number, - foo3: boolean, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: string, - foo9: string[] - ) => { - return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } - } - ) - - const res1 = selector1({ - testString: 'a', - testNumber: 42, - testBoolean: true, - testStringArray: ['b', 'c'] - }) - - const selector = createSelector( - (state: State) => state.foo, - (state: State, props: Props) => props.bar, - (foo, bar) => ({ foo, bar }) - ) - - // @ts-expect-error - selector({ foo: 'fizz' }) - // @ts-expect-error - selector({ foo: 'fizz' }, { bar: 'baz' }) - - const ret = selector({ foo: 'fizz' }, { bar: 42 }) - const foo: string = ret.foo - const bar: number = ret.bar - - const selector2 = createSelector( - (state: State) => state.foo, - (state: State) => state.foo, - (state: State) => state.foo, - (state: State) => state.foo, - (state: State) => state.foo, - (state: State, props: Props) => props.bar, - (foo1, foo2, foo3, foo4, foo5, bar) => ({ - foo1, - foo2, - foo3, - foo4, - foo5, - bar - }) - ) - - selector2({ foo: 'fizz' }, { bar: 42 }) - - const selector3 = createSelector( - (s: State) => s.foo, - (s: State, x: string) => x, - (s: State, y: number) => y, - (v, x) => { - return x + v - } - ) - - // @ts-expect-error - selector3({ foo: 'fizz' }, 42) - - const selector4 = createSelector( - (s: State, val: number) => s.foo, - (s: State, val: string | number) => val, - (foo, val) => { - return val - } - ) - - selector4({ foo: 'fizz' }, 42) -} - -function testArrayArgument() { - const selector = createSelector( - [ - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }, props: { bar: number }) => props.bar - ], - (foo1, foo2, bar) => ({ foo1, foo2, bar }) - ) - - const ret = selector({ foo: 'fizz' }, { bar: 42 }) - const foo1: string = ret.foo1 - const foo2: string = ret.foo2 - const bar: number = ret.bar - - // @ts-expect-error - createSelector([(state: { foo: string }) => state.foo]) - - // @ts-expect-error - createSelector( - [ - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo - ], - (foo: string, bar: number) => {} - ) - - createSelector( - [ - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo - ], - ( - foo1: string, - foo2: string, - foo3: string, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: string, - foo9: string, - foo10: string - ) => {} - ) - - // @ts-expect-error - createSelector( - [ - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo - ], - (foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8: number, foo9, foo10) => {} - ) - - // @ts-expect-error - createSelector( - [ - (state: { foo: string }) => state.foo, - // @ts-expect-error - state => state.foo, - // @ts-expect-error - state => state.foo, - // @ts-expect-error - state => state.foo, - // @ts-expect-error - state => state.foo, - // @ts-expect-error - state => state.foo, - // @ts-expect-error - state => state.foo, - // @ts-expect-error - state => state.foo, - 1 - ], - // We expect an error here, but the error differs between TS versions - // @ts-ignore - (foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9) => {} - ) - - const selector2 = createSelector( - [ - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo - ], - ( - foo1: string, - foo2: string, - foo3: string, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: string, - foo9: string - ) => { - return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } - } - ) - - { - const ret = selector2({ foo: 'fizz' }) - const foo1: string = ret.foo1 - const foo2: string = ret.foo2 - const foo3: string = ret.foo3 - const foo4: string = ret.foo4 - const foo5: string = ret.foo5 - const foo6: string = ret.foo6 - const foo7: string = ret.foo7 - const foo8: string = ret.foo8 - const foo9: string = ret.foo9 - // @ts-expect-error - ret.foo10 - } - - // @ts-expect-error - selector2({ foo: 'fizz' }, { bar: 42 }) - - const parametric = createSelector( - [ - (state: { foo: string }, props: { bar: number }) => props.bar, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo - ], - ( - bar: number, - foo1: string, - foo2: string, - foo3: string, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: string - ) => { - return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, bar } - } - ) - - // allows a large array of heterogeneous parameter type selectors - const correctlyTypedArraySelector = createSelector( - [ - (state: { testString: string }) => state.testString, - (state: { testNumber: number }) => state.testNumber, - (state: { testBoolean: boolean }) => state.testBoolean, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testString: string }) => state.testString, - (state: { testStringArray: string[] }) => state.testStringArray - ], - ( - foo1: string, - foo2: number, - foo3: boolean, - foo4: string, - foo5: string, - foo6: string, - foo7: string, - foo8: string, - foo9: string[] - ) => { - return { foo1, foo2, foo3, foo4, foo5, foo6, foo7, foo8, foo9 } - } - ) - - // @ts-expect-error - parametric({ foo: 'fizz' }) - - { - const ret = parametric({ foo: 'fizz' }, { bar: 42 }) - const foo1: string = ret.foo1 - const foo2: string = ret.foo2 - const foo3: string = ret.foo3 - const foo4: string = ret.foo4 - const foo5: string = ret.foo5 - const foo6: string = ret.foo6 - const foo7: string = ret.foo7 - const foo8: string = ret.foo8 - const bar: number = ret.bar - // @ts-expect-error - ret.foo9 - } -} - -function testOptionalArgumentsConflicting() { - type State = { foo: string; bar: number; baz: boolean } - - const selector = createSelector( - (state: State) => state.baz, - (state: State, arg: string) => arg, - (state: State, arg: number) => arg, - baz => { - const baz1: boolean = baz - // @ts-expect-error - const baz2: number = baz - } - ) - - // @ts-expect-error the selector above has inconsistent conflicting arguments so usage should error - selector({} as State) - // @ts-expect-error - selector({} as State, 'string') - // @ts-expect-error - selector({} as State, 1) - - const selector2 = createSelector( - (state: State, prefix: any) => prefix + state.foo, - str => str - ) - - // @ts-expect-error here we require one argument which can be anything so error if there are no arguments - selector2({} as State) - // no error passing anything in - selector2({} as State, 'blach') - selector2({} as State, 1) - - // here the argument is optional so it should be possible to omit the argument or pass anything - const selector3 = createSelector( - (state: State, prefix?: any) => prefix + state.foo, - str => str - ) - - selector3({} as State) - selector3({} as State, 1) - selector3({} as State, 'blach') - - // https://github.com/reduxjs/reselect/issues/563 - const selector4 = createSelector( - (state: State, prefix: string, suffix: any) => - prefix + state.foo + String(suffix), - str => str - ) - - // @ts-expect-error - selector4({} as State) - // @ts-expect-error - selector4({} as State, 'blach') - selector4({} as State, 'blach', 4) - - // as above but a unknown 2nd argument - const selector5 = createSelector( - (state: State, prefix: string, suffix: unknown) => - prefix + state.foo + String(suffix), - str => str - ) - - // @ts-expect-error - selector5({} as State) - // @ts-expect-error - selector5({} as State, 'blach') - selector5({} as State, 'blach', 4) - - // This next section is now obsolete with the changes in TS 4.9 - // // @ts-expect-error It would be great to delete this, it is not correct. - // // Due to what must be a TS bug? if the default parameter is used, we lose the type for prefix - // // and it is impossible to type the selector without typing prefix - // const selector6 = createSelector( - // (state: State, prefix = '') => prefix + state.foo, - // (str: string) => str - // ) - - // // because the suppressed error above, selector6 has broken typings and doesn't allow a passed parameter - // selector6({} as State) - // // @ts-expect-error would be great if we can delete this, it should not error - // selector6({} as State, 'blach') - // // @ts-expect-error wrong type - // selector6({} as State, 1) - - // this is an example fixing selector6. We have to add a un-necessary typing in and magically the types are correct - const selector7 = createSelector( - ( - state: State, - // eslint-disable-next-line @typescript-eslint/no-inferrable-types - prefix: string = 'a' - ) => prefix + state.foo, - (str: string) => str - ) - - selector7({} as State) - selector7({} as State, 'blach') - // @ts-expect-error wrong type - selector7({} as State, 1) - - const selector8 = createSelector( - (state: State, prefix: unknown) => prefix, - str => str - ) - - // @ts-expect-error needs a argument - selector8({} as State) - // allowed to pass anything as the type is unknown - selector8({} as State, 'blach') - selector8({} as State, 2) -} - -function testLruMemoize() { - const func = (a: string) => +a - - const memoized = lruMemoize(func) - - const ret0: number = memoized('42') - // @ts-expect-error - const ret1: string = memoized('42') - - const memoized2 = lruMemoize( - (str: string, arr: string[]): { str: string; arr: string[] } => ({ - str, - arr - }), - (a: T, b: T) => { - return `${a}` === `${b}` - } - ) - - const ret2 = memoized2('', ['1', '2']) - const str: string = ret2.str - const arr: string[] = ret2.arr -} - -function testCreateSelectorCreator() { - const defaultCreateSelector = createSelectorCreator(lruMemoize) - - const selector = defaultCreateSelector( - (state: { foo: string }) => state.foo, - foo => foo - ) - const value: string = selector({ foo: 'fizz' }) - - // @ts-expect-error - selector({ foo: 'fizz' }, { bar: 42 }) - - // clearCache should exist because of lruMemoize - selector.clearCache() - - const parametric = defaultCreateSelector( - (state: { foo: string }) => state.foo, - (state: { foo: string }, props: { bar: number }) => props.bar, - (foo, bar) => ({ foo, bar }) - ) - - // @ts-expect-error - parametric({ foo: 'fizz' }) - - const ret = parametric({ foo: 'fizz' }, { bar: 42 }) - const foo: string = ret.foo - const bar: number = ret.bar - - // @ts-expect-error - createSelectorCreator(lruMemoize, 1) - - createSelectorCreator(lruMemoize, (a: T, b: T) => { - return `${a}` === `${b}` - }) -} - -function testCreateStructuredSelector() { - const oneParamSelector = createStructuredSelector({ - foo: (state: StateAB) => state.a, - bar: (state: StateAB) => state.b - }) - - const threeParamSelector = createStructuredSelector({ - foo: (state: StateAB, c: number, d: string) => state.a, - bar: (state: StateAB, c: number, d: string) => state.b - }) - - interface RootState { - foo: string - bar: number - } - - const typedStructuredSelectorCreator = - createStructuredSelector.withTypes() - - const selector = typedStructuredSelectorCreator({ - foo: state => state.foo, - bar: state => +state.foo - }) - - const res1 = selector({ foo: '42', bar: 1 }) - const foo: string = res1.foo - const bar: number = res1.bar - - // @ts-expect-error - selector({ bar: '42' }) - - // @ts-expect-error - selector({ foo: '42' }, { bar: 42 }) - - typedStructuredSelectorCreator({ - // @ts-expect-error - bar: (state: { baz: boolean }) => 1 - }) - - typedStructuredSelectorCreator({ - bar: state => state.foo - }) - - typedStructuredSelectorCreator({ - baz: state => state.foo - }) - - // Test automatic inference of types for createStructuredSelector via overload - type State = { foo: string } - const FooSelector = (state: State, a: number, b: string) => state.foo - const BarSelector = (state: State, a: number, b: string) => +state.foo - - const selector2 = createStructuredSelector({ - foo: FooSelector, - bar: BarSelector - }) - - const selectorGenerics = createStructuredSelector<{ - foo: typeof FooSelector - bar: typeof BarSelector - }>({ - foo: state => state.foo, - bar: state => +state.foo - }) - - type ExpectedResult = { - foo: string - bar: number - } - - const resOneParam = oneParamSelector({ a: 1, b: 2 }) - const resThreeParams = threeParamSelector({ a: 1, b: 2 }, 99, 'blah') - const res2: ExpectedResult = selector({ foo: '42', bar: 0 }) - const res3: ExpectedResult = selector2({ foo: '42' }, 99, 'test') - const resGenerics: ExpectedResult = selectorGenerics( - { foo: '42' }, - 99, - 'test' - ) - - //@ts-expect-error - selector2({ bar: '42' }) - // @ts-expect-error - selectorGenerics({ bar: '42' }) -} - -// TODO: Remove this function once `TypedStructuredSelectorCreator` is removed. -function testTypedCreateStructuredSelector() { - type RootState = { - foo: string - bar: number - } - - const selectFoo = (state: RootState) => state.foo - const selectBar = (state: RootState) => state.bar - - const typedStructuredSelectorCreator: TypedStructuredSelectorCreator = - createStructuredSelector - - typedStructuredSelectorCreator({ - foo: selectFoo, - bar: selectBar - }) - - // @ts-expect-error Because `bar` is missing. - typedStructuredSelectorCreator({ - foo: selectFoo - }) - - // This works - const selectorGenerics = createStructuredSelector<{ - foo: typeof selectFoo - bar: typeof selectBar - }>({ - foo: state => state.foo, - bar: state => +state.foo - }) - - // This also works - const selectorGenerics1 = typedStructuredSelectorCreator<{ - foo: typeof selectFoo - bar: typeof selectBar - }>({ - foo: state => state.foo, - bar: state => +state.foo - }) - - // Their types are the same. - expectExactType(selectorGenerics) -} - -function testDynamicArrayArgument() { - interface Elem { - val1: string - val2: string - } - const data: ReadonlyArray = [ - { val1: 'a', val2: 'aa' }, - { val1: 'b', val2: 'bb' } - ] - - createSelector( - data.map(obj => () => obj.val1), - (...vals) => vals.join(',') - ) - - createSelector( - data.map(obj => () => obj.val1), - // @ts-expect-error - vals => vals.join(',') - ) - - createSelector( - data.map(obj => () => obj.val1), - (...vals: string[]) => 0 - ) - // @ts-expect-error - createSelector( - data.map(obj => () => obj.val1), - (...vals: number[]) => 0 - ) - - const s = createSelector( - data.map(obj => (state: StateA, fld: keyof Elem) => obj[fld]), - (...vals) => vals.join(',') - ) - s({ a: 42 }, 'val1') - s({ a: 42 }, 'val2') - // @ts-expect-error - s({ a: 42 }, 'val3') -} - -function testStructuredSelectorTypeParams() { - type GlobalState = { - foo: string - bar: number - } - - const selectFoo = (state: GlobalState) => state.foo - const selectBar = (state: GlobalState) => state.bar - - // Output state should be the same as input, if not provided - // @ts-expect-error - createStructuredSelector({ - foo: selectFoo - // bar: selectBar, - // ^^^ because this is missing, an error is thrown - }) -} - -function multiArgMemoize any>( - func: F, - a: number, - b: string, - equalityCheck = referenceEqualityCheck -): F { - // @ts-ignore - return () => {} -} - -// #384: check for lruMemoize - -{ - interface Transaction { - transactionId: string - } - - const toId = (transaction: Transaction) => transaction.transactionId - const transactionsIds = (transactions: Transaction[]) => - transactions.map(toId) - const collectionsEqual = (ts1: Transaction[], ts2: Transaction[]) => - isEqual(transactionsIds(ts1), transactionsIds(ts2)) - - const createTransactionsSelector = createSelectorCreator( - lruMemoize, - collectionsEqual - ) - - const createMultiMemoizeArgSelector = createSelectorCreator( - multiArgMemoize, - 42, - 'abcd', - referenceEqualityCheck - ) - - const select = createMultiMemoizeArgSelector( - (state: { foo: string }) => state.foo, - foo => foo + '!' - ) - // error is not applicable anymore - select.clearCache() - - const createMultiMemoizeArgSelector2 = createSelectorCreator( - multiArgMemoize, - 42, - // @ts-expect-error - referenceEqualityCheck - ) - - const groupTransactionsByLabel = lruMemoize( - (transactions: Transaction[]) => - groupBy(transactions, item => item.transactionId), - collectionsEqual - ) -} - -// #445 -function issue445() { - interface TestState { - someNumber: number | null - someString: string | null - } - - interface Object1 { - str: string - } - interface Object2 { - num: number - } - - const getNumber = (state: TestState) => state.someNumber - const getString = (state: TestState) => state.someString - - function generateObject1(str: string): Object1 { - return { - str - } - } - function generateObject2(num: number): Object2 { - return { - num - } - } - function generateComplexObject( - num: number, - subObject: Object1, - subObject2: Object2 - ): boolean { - return true - } - - // ################ Tests ################ - - // Compact selector examples - - // Should error because generateObject1 can't take null - // @ts-expect-error - const getObject1 = createSelector([getString], generateObject1) - - // Should error because generateObject2 can't take null - // @ts-expect-error - const getObject2 = createSelector([getNumber], generateObject2) - - // Should error because mismatch of params - // @ts-expect-error - const getComplexObjectTest1 = createSelector( - [getObject1], - generateComplexObject - ) - - // Does error, but error is really weird and talks about "Object1 is not assignable to type number" - // @ts-expect-error - const getComplexObjectTest2 = createSelector( - [getNumber, getObject1], - generateComplexObject - ) - - // Should error because number can't be null - // @ts-expect-error - const getComplexObjectTest3 = createSelector( - [getNumber, getObject1, getObject2], - generateComplexObject - ) - - // Does error, but error is really weird and talks about "Object1 is not assignable to type number" - // @ts-expect-error - const getComplexObjectTest4 = createSelector( - [getObject1, getNumber, getObject2], - generateComplexObject - ) - - // Verbose selector examples - - // Errors correctly, says str can't be null - const getVerboseObject1 = createSelector([getString], str => - // @ts-expect-error - generateObject1(str) - ) - - // Errors correctly, says num can't be null - const getVerboseObject2 = createSelector([getNumber], num => - // @ts-expect-error - generateObject2(num) - ) - - // Errors correctly - const getVerboseComplexObjectTest1 = createSelector([getObject1], obj1 => - // @ts-expect-error - generateComplexObject(obj1) - ) - - // Errors correctly - const getVerboseComplexObjectTest2 = createSelector( - [getNumber, getObject1], - // @ts-expect-error - (num, obj1) => generateComplexObject(num, obj1) - ) - - // Errors correctly - const getVerboseComplexObjectTest3 = createSelector( - [getNumber, getObject1, getObject2], - // @ts-expect-error - (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) - ) - - // Errors correctly - const getVerboseComplexObjectTest4 = createSelector( - [getObject1, getNumber, getObject2], - // @ts-expect-error - (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) - ) -} - -// #492 -function issue492() { - const fooPropSelector = (_: {}, ownProps: { foo: string }) => ownProps.foo - const fooBarPropsSelector = ( - _: {}, - ownProps: { foo: string; bar: string } - ) => [ownProps.foo, ownProps.bar] - - const combinedSelector = createSelector( - fooPropSelector, - fooBarPropsSelector, - (foo, fooBar) => fooBar - ) -} - -function customMemoizationOptionTypes() { - const customMemoize = ( - f: (...args: any[]) => any, - a: string, - b: number, - c: boolean - ) => { - return f - } - - const customSelectorCreatorCustomMemoizeWorking = createSelectorCreator( - customMemoize, - 'a', - 42, - true - ) - - // @ts-expect-error - const customSelectorCreatorCustomMemoizeMissingArg = createSelectorCreator( - customMemoize, - 'a', - true - ) -} - -// createSelector config options -function createSelectorConfigOptions() { - const lruMemoizeAcceptsFirstArgDirectly = createSelector( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoize: lruMemoize, - memoizeOptions: (a, b) => a === b - } - ) - - const lruMemoizeAcceptsFirstArgAsObject = createSelector( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoize: lruMemoize, - memoizeOptions: { - equalityCheck: (a, b) => a === b - } - } - ) - - const lruMemoizeAcceptsArgsAsArray = createSelector( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoize: lruMemoize, - memoizeOptions: [(a, b) => a === b] - } - ) - - const customSelectorCreatorMicroMemoize = createSelectorCreator( - microMemoize, - { - maxSize: 42 - } - ) - - customSelectorCreatorMicroMemoize( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoizeOptions: [ - { - maxSize: 42 - } - ] - } - ) - - const customSelectorCreatorMemoizeOne = createSelectorCreator(memoizeOne) - - customSelectorCreatorMemoizeOne( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoizeOptions: (a, b) => a === b - } - ) -} - -// Verify more than 12 selectors are accepted -// Issue #525 -const withLotsOfInputSelectors = createSelector( - (_state: StateA) => 1, - (_state: StateA) => 2, - (_state: StateA) => 3, - (_state: StateA) => 4, - (_state: StateA) => 5, - (_state: StateA) => 6, - (_state: StateA) => 7, - (_state: StateA) => 8, - (_state: StateA) => 9, - (_state: StateA) => 10, - (_state: StateA) => 11, - (_state: StateA) => 12, - (_state: StateA) => 13, - (_state: StateA) => 14, - (_state: StateA) => 15, - (_state: StateA) => 16, - (_state: StateA) => 17, - (_state: StateA) => 18, - (_state: StateA) => 19, - (_state: StateA) => 20, - (_state: StateA) => 21, - (_state: StateA) => 22, - (_state: StateA) => 23, - (_state: StateA) => 24, - (_state: StateA) => 25, - (_state: StateA) => 26, - (_state: StateA) => 27, - (_state: StateA) => 28, - (...args) => args.length -) - -type SelectorArray29 = [ - (_state: StateA) => 1, - (_state: StateA) => 2, - (_state: StateA) => 3, - (_state: StateA) => 4, - (_state: StateA) => 5, - (_state: StateA) => 6, - (_state: StateA) => 7, - (_state: StateA) => 8, - (_state: StateA) => 9, - (_state: StateA) => 10, - (_state: StateA) => 11, - (_state: StateA) => 12, - (_state: StateA) => 13, - (_state: StateA) => 14, - (_state: StateA) => 15, - (_state: StateA) => 16, - (_state: StateA) => 17, - (_state: StateA) => 18, - (_state: StateA) => 19, - (_state: StateA) => 20, - (_state: StateA) => 21, - (_state: StateA) => 22, - (_state: StateA) => 23, - (_state: StateA) => 24, - (_state: StateA) => 25, - (_state: StateA) => 26, - (_state: StateA) => 27, - (_state: StateA) => 28, - (_state: StateA) => 29 -] - -type Results = SelectorResultArray -type State = GetStateFromSelectors - -// Ensure that input functions with mismatched states raise errors -{ - const input1 = (state: string) => 1 - const input2 = (state: number) => 2 - - const selector = createSelector(input1, input2, (...args) => 0) - // @ts-expect-error - selector('foo') - // @ts-expect-error - selector(5) -} -{ - const selector = createSelector( - (state: { foo: string }) => 1, - (state: { bar: string }) => 2, - (...args) => 0 - ) - selector({ foo: '', bar: '' }) - // @ts-expect-error - selector({ foo: '' }) - // @ts-expect-error - selector({ bar: '' }) -} - -{ - const selector = createSelector( - (state: { foo: string }) => 1, - (state: { foo: string }) => 2, - (...args) => 0 - ) - // @ts-expect-error - selector({ foo: '', bar: '' }) - selector({ foo: '' }) - // @ts-expect-error - selector({ bar: '' }) -} - -// Issue #526 -function testInputSelectorWithUndefinedReturn() { - type Input = { field: number | undefined } - type Output = string - type SelectorType = (input: Input) => Output - - const input = ({ field }: Input) => field - const result = (out: number | undefined): Output => 'test' - - // Make sure the selector type is honored - const selector: SelectorType = createSelector( - ({ field }: Input) => field, - args => 'test' - ) - - // even when memoizeOptions are passed - const selector2: SelectorType = createSelector( - ({ field }: Input) => field, - args => 'test', - { - memoize: lruMemoize, - memoizeOptions: { maxSize: 42 } - } - ) - - // Make sure inference of functions works... - const selector3: SelectorType = createSelector(input, result) - const selector4: SelectorType = createSelector(input, result, { - memoize: lruMemoize, - memoizeOptions: { maxSize: 42 } - }) -} - -function deepNesting() { - type State = { foo: string } - const readOne = (state: State) => state.foo - - const selector0 = createSelector(readOne, one => one) - const selector1 = createSelector(selector0, s => s) - const selector2 = createSelector(selector1, s => s) - const selector3 = createSelector(selector2, s => s) - const selector4 = createSelector(selector3, s => s) - const selector5 = createSelector(selector4, s => s) - const selector6 = createSelector(selector5, s => s) - const selector7 = createSelector(selector6, s => s) - const selector8 = createSelector(selector7, s => s) - const selector9 = createSelector(selector8, s => s) - const selector10 = createSelector(selector9, s => s) - const selector11 = createSelector(selector10, s => s) - const selector12 = createSelector(selector11, s => s) - const selector13 = createSelector(selector12, s => s) - const selector14 = createSelector(selector13, s => s) - const selector15 = createSelector(selector14, s => s) - const selector16 = createSelector(selector15, s => s) - const selector17 = createSelector(selector16, s => s) - const selector18 = createSelector(selector17, s => s) - const selector19 = createSelector(selector18, s => s) - const selector20 = createSelector(selector19, s => s) - const selector21 = createSelector(selector20, s => s) - const selector22 = createSelector(selector21, s => s) - const selector23 = createSelector(selector22, s => s) - const selector24 = createSelector(selector23, s => s) - const selector25 = createSelector(selector24, s => s) - const selector26 = createSelector(selector25, s => s) - const selector27 = createSelector(selector26, s => s) - const selector28 = createSelector(selector27, s => s) - const selector29 = createSelector(selector28, s => s) -} - -function issue540() { - const input1 = ( - _: StateA, - { testNumber }: { testNumber: number }, - c: number, - d: string - ) => testNumber - - const input2 = ( - _: StateA, - { testString }: { testString: string }, - c: number | string - ) => testString - - const input3 = ( - _: StateA, - { testBoolean }: { testBoolean: boolean }, - c: number | string, - d: string - ) => testBoolean - - const input4 = (_: StateA, { testString2 }: { testString2: string }) => - testString2 - - const testSelector = createSelector( - input1, - input2, - input3, - input4, - (testNumber, testString, testBoolean) => testNumber + testString - ) - - const state: StateA = { a: 42 } - const test = testSelector( - state, - { testNumber: 1, testString: '10', testBoolean: true, testString2: 'blah' }, - 42, - 'blah' - ) - - // #541 - const selectProp1 = createSelector( - [ - (state: StateA) => state, - (state: StateA, props: { prop1: number }) => props - ], - (state, { prop1 }) => [state, prop1] - ) - - const selectProp2 = createSelector( - [selectProp1, (state, props: { prop2: number }) => props], - (state, { prop2 }) => [state, prop2] - ) - - selectProp1({ a: 42 }, { prop1: 1 }) - // @ts-expect-error - selectProp2({ a: 42 }, { prop2: 2 }) -} - -function issue548() { - interface State { - value: Record | null - loading: boolean - } - - interface Props { - currency: string - } - - const isLoading = createSelector( - (state: State) => state, - (_: State, props: Props) => props.currency, - ({ loading }, currency) => loading - ) - - const mapData = createStructuredSelector({ - isLoading, - test2: (state: State) => 42 - }) - - const result = mapData({ value: null, loading: false }, { currency: 'EUR' }) -} - -function issue550() { - const some = createSelector( - (a: number) => a, - (_a: number, b: number) => b, - (a, b) => a + b - ) - - const test = some(1, 2) -} - -function rtkIssue1750() { - const slice = createSlice({ - name: 'test', - initialState: 0, - reducers: {} - }) - - interface Pokemon { - name: string - } - - // Define a service using a base URL and expected endpoints - const pokemonApi = createApi({ - reducerPath: 'pokemonApi', - baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }), - endpoints: builder => ({ - getPokemonByName: builder.query({ - query: name => `pokemon/${name}` - }) - }) - }) - - const store = configureStore({ - reducer: { - test: slice.reducer, - [pokemonApi.reducerPath]: pokemonApi.reducer - }, - middleware: getDefaultMiddleware => - getDefaultMiddleware().concat(pokemonApi.middleware) - }) - - type RootState = ReturnType - - const selectTest = createSelector( - (state: RootState) => state.test, - test => test - ) - - const useAppSelector: TypedUseSelectorHook = useSelector - - // Selector usage should compile correctly - const testItem = selectTest(store.getState()) - - function App() { - const test = useAppSelector(selectTest) - return null - } -} - -function handleNestedIncompatTypes() { - // Incompatible parameters should force errors even for nested fields. - // One-level-deep fields get stripped to empty objects, so they - // should be replaced with `never`. - // Deeper fields should get caught by TS. - // Playground: https://tsplay.dev/wg6X0W - const input1a = (_: StateA, param: { b: number }) => param.b - - const input1b = (_: StateA, param: { b: string }) => param.b - - const testSelector1 = createSelector(input1a, input1b, () => ({})) - - // @ts-expect-error - testSelector1({ a: 42 }, { b: 99 }) // should not compile - - const input2a = (_: StateA, param: { b: { c: number } }) => param.b.c - const input2b = (_: StateA, param: { b: { c: string } }) => param.b.c - - const testSelector2 = createSelector(input2a, input2b, (c1, c2) => {}) - - // @ts-expect-error - testSelector2({ a: 42 }, { b: { c: 99 } }) -} - -function issue554a() { - interface State { - foo: string - bar: number - } - - const initialState: State = { - foo: 'This is Foo', - bar: 1 - } - - const getFoo = (state: State) => { - return state.foo - } - getFoo(initialState) - - const getBar = (state: State) => { - return state.bar - } - getBar(initialState) - - const simple = createSelector(getFoo, getBar, (foo, bar) => { - return `${foo} => ${bar}` - }) - simple(initialState) - - // Input selectors with positional args - const firstInput = (_: State, first: string) => first - // Skip the first arg and return only the second. - const secondInput = (_: State, _first: string, second: number) => second - - const complexOne = createSelector( - getFoo, - getBar, - firstInput, - (foo, bar, first) => { - return `${foo} => ${bar} || ${first}` - } - ) - complexOne(initialState, 'first') - - const complexTwo = createSelector( - getFoo, - getBar, - firstInput, - secondInput, - (foo, bar, first, second) => { - return `${foo} => ${bar} || ${first} and ${second}` - } - ) - // TS should complain since 'second' should be `number` - // @ts-expect-error - complexTwo(initialState, 'first', 'second') -} - -function issue554b() { - interface State { - counter1: number - counter2: number - } - - const selectTest = createSelector( - (state: State, numberA?: number) => numberA, - (state: State) => state.counter2, - (numberA, counter2) => (numberA ? numberA + counter2 : counter2) - ) - - type selectTestParams = Parameters - const p1: selectTestParams = [{ counter1: 1, counter2: 2 }, 42] - expectExactType<[State, number?]>(p1) - - const result = selectTest({ counter1: 1, counter2: 2 }, 42) -} - -function issue554c() { - interface State { - counter1: number - counter2: number - } - - const selectTest = createSelector( - (state: State, numberA?: number) => numberA, // `numberA` is optional - (state: State) => state.counter2, - (numberA, counter2) => (numberA ? numberA + counter2 : counter2) - ) - - // @ts-expect-error - const value = selectTest({ counter1: 0, counter2: 0 }, 'what?') - - const selectTest2 = createSelector( - (state: State, numberA: number) => numberA, // `numberA` is not optional anymore - (state: State) => state.counter2, - (numberA, counter2) => (numberA ? numberA + counter2 : counter2) - ) - - // @ts-expect-error - const value2 = selectTest2({ counter1: 0, counter2: 0 }, 'what?') -} - -function issue555() { - type IReduxState = { - ui: { - x: string - y: string - } - } - - const someSelector1 = createSelector( - (state: IReduxState, param: 'x' | 'y' | undefined) => - param !== undefined ? state.ui[param] : null, - (a: string | null) => a - ) - - const someSelector2 = createSelector( - (state: IReduxState, param?: 'x' | 'y') => - param !== undefined ? state.ui[param] : null, - (a: string | null) => a - ) - - const someSelector3 = createSelector( - (state: IReduxState, param: 'x' | 'y' | null) => - param !== null ? state.ui[param] : null, - (a: string | null) => a - ) - - const state = { ui: { x: '1', y: '2' } } - - const selectorResult1 = someSelector1(state, undefined) - const selectorResult2 = someSelector2(state, undefined) - const selectorResult3 = someSelector3(state, null) -} - -function testCreateStructuredSelectorNew() { - interface State { - todos: { - id: number - completed: boolean - }[] - } - const state: State = { - todos: [ - { id: 0, completed: false }, - { id: 1, completed: false } - ] - } - - const selectorDefaultParametric = createSelector( - (state: State, id: number) => id, - (state: State) => state.todos, - (id, todos) => todos.filter(todo => todo.id === id) - ) - const multiArgsStructuredSelector = createStructuredSelector( - { - selectedTodos: (state: State) => state.todos, - selectedTodoById: (state: State, id: number) => state.todos[id], - selectedCompletedTodos: ( - state: State, - id: number, - isCompleted: boolean - ) => state.todos.filter(({ completed }) => completed === isCompleted) - }, - createSelectorCreator({ memoize: microMemoize, argsMemoize: microMemoize }) - ) - - multiArgsStructuredSelector.resultFunc( - [{ id: 2, completed: true }], - { id: 0, completed: false }, - [{ id: 0, completed: false }] - ).selectedCompletedTodos - - multiArgsStructuredSelector.memoizedResultFunc( - [{ id: 2, completed: true }], - { id: 0, completed: false }, - [{ id: 0, completed: false }] - ).selectedCompletedTodos - - multiArgsStructuredSelector.memoizedResultFunc.cache - multiArgsStructuredSelector.memoizedResultFunc.fn - multiArgsStructuredSelector.memoizedResultFunc.isMemoized - multiArgsStructuredSelector.memoizedResultFunc.options - - multiArgsStructuredSelector(state, 2, true).selectedCompletedTodos - expectExactType(multiArgsStructuredSelector.argsMemoize) - expectExactType(multiArgsStructuredSelector.memoize) - expectExactType< - [ - (state: State) => State['todos'], - (state: State, id: number) => State['todos'][number], - (state: State, id: number, isCompleted: boolean) => State['todos'] - ] - >(multiArgsStructuredSelector.dependencies) - // @ts-expect-error Wrong number of arguments. - multiArgsStructuredSelector(state, 2) -} diff --git a/typescript_test/tsconfig.json b/typescript_test/tsconfig.json deleted file mode 100644 index 81026e74a..000000000 --- a/typescript_test/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "strict": true, - "target": "ES2015", - "lib": ["ES2021.WeakRef"], - "declaration": true, - "noEmit": true, - "skipLibCheck": true, - "paths": { - "reselect": ["../src/index"], // @remap-prod-remove-line - "@internal/*": ["../src/*"] - } - }, - "include": ["test.ts", "argsMemoize.typetest.ts"] -} diff --git a/typescript_test/typesTestUtils.ts b/typescript_test/typesTestUtils.ts deleted file mode 100644 index c27892f29..000000000 --- a/typescript_test/typesTestUtils.ts +++ /dev/null @@ -1,29 +0,0 @@ -export function expectType(t: T): T { - return t -} - -export declare type IsAny = true | false extends ( - T extends never ? true : false -) - ? True - : False - -export declare type IsUnknown = unknown extends T - ? IsAny - : False - -type Equals = IsAny< - T, - never, - IsAny -> - -export type IsEqual = (() => G extends A ? 1 : 2) extends < - G ->() => G extends B ? 1 : 2 - ? true - : false - -export function expectExactType(t: T) { - return (u: U & Equals) => {} -} diff --git a/vitest.config.mts b/vitest.config.mts index b45318ec5..7b527ac63 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -1,23 +1,19 @@ import { defineConfig } from 'vitest/config' -import path from 'node:path' -import { fileURLToPath } from 'node:url' - -// No __dirname under Node ESM -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) - export default defineConfig({ test: { - typecheck: { tsconfig: 'type-tests/tsconfig.json' }, + pool: 'threads', + watch: false, globals: true, - include: ['./test/**/*.(spec|test).[jt]s?(x)'], - setupFiles: ['test/setup.vitest.ts'], + setupFiles: ['test/setup.ts'], alias: { - reselect: path.join(__dirname, 'src/index.ts'), // @remap-prod-remove-line + reselect: new URL( + process.env.TEST_DIST ? 'node_modules/reselect' : 'src/index.ts', + import.meta.url + ).pathname, // this mapping is disabled as we want `dist` imports in the tests only to be used for "type-only" imports which don't play a role for jest - '@internal': path.join(__dirname, 'src') + '@internal': new URL('src', import.meta.url).pathname } } }) diff --git a/yarn.lock b/yarn.lock index c9f4677c9..8c1ff5798 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,16 +5,16 @@ __metadata: version: 8 cacheKey: 10 -"@asamuzakjp/css-color@npm:^3.1.1": - version: 3.1.1 - resolution: "@asamuzakjp/css-color@npm:3.1.1" +"@asamuzakjp/css-color@npm:^3.1.2": + version: 3.1.5 + resolution: "@asamuzakjp/css-color@npm:3.1.5" dependencies: - "@csstools/css-calc": "npm:^2.1.2" - "@csstools/css-color-parser": "npm:^3.0.8" + "@csstools/css-calc": "npm:^2.1.3" + "@csstools/css-color-parser": "npm:^3.0.9" "@csstools/css-parser-algorithms": "npm:^3.0.4" "@csstools/css-tokenizer": "npm:^3.0.3" lru-cache: "npm:^10.4.3" - checksum: 10/42dd131c3f6297259b353b6a226e782800babe64003e41f3598e3fe98543eecea2a5d9c1869ed1c853b639ed9e259c685c6b7c96d1e0b5c0d154f874a8a8c3d9 + checksum: 10/a7818c84c13a8b7bf586f7ab5160435c55de54399cef54592971177211ea062b771b7d42f893e608228d21981aad9b0ecbe72f45b890af9f7e60ae43cb615561 languageName: node linkType: hard @@ -48,11 +48,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.12.5": - version: 7.26.10 - resolution: "@babel/runtime@npm:7.26.10" + version: 7.27.0 + resolution: "@babel/runtime@npm:7.27.0" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10/9d7ff8e96abe3791047c1138789c742411e3ef19c4d7ca18ce916f83cec92c06ec5dc64401759f6dd1e377cf8a01bbd2c62e033eb7550f435cf6579768d0d4a5 + checksum: 10/e6966e03b695feb4c0ac0856a4355231c2580bf9ebd0298f47739f85c0ea658679dd84409daf26378d42c86c1cbe7e33feab709b14e784254b6c441d91606465 languageName: node linkType: hard @@ -63,26 +63,26 @@ __metadata: languageName: node linkType: hard -"@csstools/css-calc@npm:^2.1.2": - version: 2.1.2 - resolution: "@csstools/css-calc@npm:2.1.2" +"@csstools/css-calc@npm:^2.1.3": + version: 2.1.3 + resolution: "@csstools/css-calc@npm:2.1.3" peerDependencies: "@csstools/css-parser-algorithms": ^3.0.4 "@csstools/css-tokenizer": ^3.0.3 - checksum: 10/23ba633b15ba733f9da6d65e6a97a34116d10add7df15f6b05df93f00bb47b335a2268fcfd93c442da5d4678706f7bb26ffcc26a74621e34fe0d399bb27e53d3 + checksum: 10/0c20165f13135bb51ef397c4ea8e185c75ff379378212952af57052de96890a1eda056b2c6a2d573ea69e56c9dae79a906a2e4cac9d731dfbf19defaf943fd55 languageName: node linkType: hard -"@csstools/css-color-parser@npm:^3.0.8": - version: 3.0.8 - resolution: "@csstools/css-color-parser@npm:3.0.8" +"@csstools/css-color-parser@npm:^3.0.9": + version: 3.0.9 + resolution: "@csstools/css-color-parser@npm:3.0.9" dependencies: "@csstools/color-helpers": "npm:^5.0.2" - "@csstools/css-calc": "npm:^2.1.2" + "@csstools/css-calc": "npm:^2.1.3" peerDependencies: "@csstools/css-parser-algorithms": ^3.0.4 "@csstools/css-tokenizer": ^3.0.3 - checksum: 10/935d0d6b484ee3b38390c765c66b0bb6632ca4172f211ef87f259a193bdae7f818732e8ef214fcce06016d5cf8fa1d917c24e4ff42f7359f589a979acc7e4511 + checksum: 10/634ee3c5424e21bda414015d20e906a620d06186fe38957479a5266ded435ae14675e3085a259cec75cd7138df081357aba58a2626592d61335228a451db3eca languageName: node linkType: hard @@ -102,182 +102,189 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/aix-ppc64@npm:0.23.0" +"@esbuild/aix-ppc64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/aix-ppc64@npm:0.25.3" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/android-arm64@npm:0.23.0" +"@esbuild/android-arm64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/android-arm64@npm:0.25.3" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/android-arm@npm:0.23.0" +"@esbuild/android-arm@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/android-arm@npm:0.25.3" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/android-x64@npm:0.23.0" +"@esbuild/android-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/android-x64@npm:0.25.3" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/darwin-arm64@npm:0.23.0" +"@esbuild/darwin-arm64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/darwin-arm64@npm:0.25.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/darwin-x64@npm:0.23.0" +"@esbuild/darwin-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/darwin-x64@npm:0.25.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/freebsd-arm64@npm:0.23.0" +"@esbuild/freebsd-arm64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/freebsd-arm64@npm:0.25.3" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/freebsd-x64@npm:0.23.0" +"@esbuild/freebsd-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/freebsd-x64@npm:0.25.3" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-arm64@npm:0.23.0" +"@esbuild/linux-arm64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-arm64@npm:0.25.3" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-arm@npm:0.23.0" +"@esbuild/linux-arm@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-arm@npm:0.25.3" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-ia32@npm:0.23.0" +"@esbuild/linux-ia32@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-ia32@npm:0.25.3" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-loong64@npm:0.23.0" +"@esbuild/linux-loong64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-loong64@npm:0.25.3" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-mips64el@npm:0.23.0" +"@esbuild/linux-mips64el@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-mips64el@npm:0.25.3" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-ppc64@npm:0.23.0" +"@esbuild/linux-ppc64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-ppc64@npm:0.25.3" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-riscv64@npm:0.23.0" +"@esbuild/linux-riscv64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-riscv64@npm:0.25.3" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-s390x@npm:0.23.0" +"@esbuild/linux-s390x@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-s390x@npm:0.25.3" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/linux-x64@npm:0.23.0" +"@esbuild/linux-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/linux-x64@npm:0.25.3" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/netbsd-x64@npm:0.23.0" +"@esbuild/netbsd-arm64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/netbsd-arm64@npm:0.25.3" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/netbsd-x64@npm:0.25.3" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/openbsd-arm64@npm:0.23.0" +"@esbuild/openbsd-arm64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/openbsd-arm64@npm:0.25.3" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/openbsd-x64@npm:0.23.0" +"@esbuild/openbsd-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/openbsd-x64@npm:0.25.3" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/sunos-x64@npm:0.23.0" +"@esbuild/sunos-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/sunos-x64@npm:0.25.3" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/win32-arm64@npm:0.23.0" +"@esbuild/win32-arm64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/win32-arm64@npm:0.25.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/win32-ia32@npm:0.23.0" +"@esbuild/win32-ia32@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/win32-ia32@npm:0.25.3" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.23.0": - version: 0.23.0 - resolution: "@esbuild/win32-x64@npm:0.23.0" +"@esbuild/win32-x64@npm:0.25.3": + version: 0.25.3 + resolution: "@esbuild/win32-x64@npm:0.25.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": - version: 4.5.0 - resolution: "@eslint-community/eslint-utils@npm:4.5.0" + version: 4.6.1 + resolution: "@eslint-community/eslint-utils@npm:4.6.1" dependencies: eslint-visitor-keys: "npm:^3.4.3" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10/f926c6a1510ae94ab5ce8ee0d5d8e245e0067e8ef7b25e4a430020e82ba9462a4a15b15187bffb2c45eebaa8b2591d5ac31e06a85dffd6292ccd6eaa17f23952 + checksum: 10/9f1a91bddf0a68b2b8bb71b3390d0e665e842770ff4a0188d38199e8a66ac050608da14eb614d211535ed312633d9dc237bd297857bf0e78abac927029909e50 languageName: node linkType: hard @@ -360,15 +367,6 @@ __metadata: languageName: node linkType: hard -"@jest/schemas@npm:^29.6.3": - version: 29.6.3 - resolution: "@jest/schemas@npm:29.6.3" - dependencies: - "@sinclair/typebox": "npm:^0.27.8" - checksum: 10/910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 - languageName: node - linkType: hard - "@jridgewell/gen-mapping@npm:^0.3.2": version: 0.3.8 resolution: "@jridgewell/gen-mapping@npm:0.3.8" @@ -468,9 +466,11 @@ __metadata: linkType: hard "@reduxjs/toolkit@npm:^2.0.1": - version: 2.6.1 - resolution: "@reduxjs/toolkit@npm:2.6.1" + version: 2.7.0 + resolution: "@reduxjs/toolkit@npm:2.7.0" dependencies: + "@standard-schema/spec": "npm:^1.0.0" + "@standard-schema/utils": "npm:^0.3.0" immer: "npm:^10.0.3" redux: "npm:^5.0.1" redux-thunk: "npm:^3.1.0" @@ -483,147 +483,161 @@ __metadata: optional: true react-redux: optional: true - checksum: 10/62ad00b875115eb2fb5b776665d2dbe71b1ad98f4342f409c67dfb27bd0cd7a13dffd7343bee6f232d0498429361f95541993bb2ecd747ad09a55069bc43303e + checksum: 10/cc264efc95f9ebeafa469bf1040d106a33768a802e6f46aa678bf9f26822d049c18b5f10864aa8badb2e62febe58e242860256174528e62b09e8f897d32cd182 languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.35.0" +"@rollup/rollup-android-arm-eabi@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.40.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-android-arm64@npm:4.35.0" +"@rollup/rollup-android-arm64@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-android-arm64@npm:4.40.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.35.0" +"@rollup/rollup-darwin-arm64@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.40.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.35.0" +"@rollup/rollup-darwin-x64@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.40.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.35.0" +"@rollup/rollup-freebsd-arm64@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.40.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-freebsd-x64@npm:4.35.0" +"@rollup/rollup-freebsd-x64@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.40.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.40.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.35.0" +"@rollup/rollup-linux-arm-musleabihf@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.40.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.35.0" +"@rollup/rollup-linux-arm64-gnu@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.40.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.35.0" +"@rollup/rollup-linux-arm64-musl@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.40.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0" +"@rollup/rollup-linux-loongarch64-gnu@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.40.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.35.0" +"@rollup/rollup-linux-riscv64-gnu@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.40.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.35.0" +"@rollup/rollup-linux-riscv64-musl@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.40.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.40.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.35.0" +"@rollup/rollup-linux-x64-gnu@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.40.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.35.0" +"@rollup/rollup-linux-x64-musl@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.40.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.35.0" +"@rollup/rollup-win32-arm64-msvc@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.40.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.35.0" +"@rollup/rollup-win32-ia32-msvc@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.40.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.35.0" +"@rollup/rollup-win32-x64-msvc@npm:4.40.0": + version: 4.40.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.40.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@sinclair/typebox@npm:^0.27.8": - version: 0.27.8 - resolution: "@sinclair/typebox@npm:0.27.8" - checksum: 10/297f95ff77c82c54de8c9907f186076e715ff2621c5222ba50b8d40a170661c0c5242c763cba2a4791f0f91cb1d8ffa53ea1d7294570cf8cd4694c0e383e484d +"@standard-schema/spec@npm:^1.0.0": + version: 1.0.0 + resolution: "@standard-schema/spec@npm:1.0.0" + checksum: 10/aee780cc1431888ca4b9aba9b24ffc8f3073fc083acc105e3951481478a2f4dc957796931b2da9e2d8329584cf211e4542275f188296c1cdff3ed44fd93a8bc8 + languageName: node + linkType: hard + +"@standard-schema/utils@npm:^0.3.0": + version: 0.3.0 + resolution: "@standard-schema/utils@npm:0.3.0" + checksum: 10/7084f875d322792f2e0a5904009434c8374b9345b09ba89828b68fd56fa3c2b366d35bf340d9e8c72736ef01793c2f70d350c372ed79845dc3566c58d34b4b51 languageName: node linkType: hard @@ -664,10 +678,10 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:1.0.6, @types/estree@npm:^1.0.0": - version: 1.0.6 - resolution: "@types/estree@npm:1.0.6" - checksum: 10/9d35d475095199c23e05b431bcdd1f6fec7380612aed068b14b2a08aa70494de8a9026765a5a91b1073f636fb0368f6d8973f518a31391d519e20c59388ed88d +"@types/estree@npm:1.0.7, @types/estree@npm:^1.0.0": + version: 1.0.7 + resolution: "@types/estree@npm:1.0.7" + checksum: 10/419c845ece767ad4b21171e6e5b63dabb2eb46b9c0d97361edcd9cabbf6a95fcadb91d89b5fa098d1336fa0b8fceaea82fca97a2ef3971f5c86e53031e157b21 languageName: node linkType: hard @@ -702,12 +716,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*": - version: 22.13.10 - resolution: "@types/node@npm:22.13.10" +"@types/node@npm:*, @types/node@npm:^22.15.2": + version: 22.15.2 + resolution: "@types/node@npm:22.15.2" dependencies: - undici-types: "npm:~6.20.0" - checksum: 10/57dc6a5e0110ca9edea8d7047082e649fa7fa813f79e4a901653b9174141c622f4336435648baced5b38d9f39843f404fa2d8d7a10981610da26066bc8caab48 + undici-types: "npm:~6.21.0" + checksum: 10/e22071571205413518aa3710644ed9603d8f4a417fc59f0e180240e1c05aaf7fb8feecdf553a2da305247b3533d03b58eab6e333115f01f581b9139a6b1dcd47 languageName: node linkType: hard @@ -719,28 +733,28 @@ __metadata: linkType: hard "@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.17": - version: 18.3.5 - resolution: "@types/react-dom@npm:18.3.5" + version: 18.3.6 + resolution: "@types/react-dom@npm:18.3.6" peerDependencies: "@types/react": ^18.0.0 - checksum: 10/02095b326f373867498e0eb2b5ebb60f9bd9535db0d757ea13504c4b7d75e16605cf1d43ce7a2e67893d177b51db4357cabb2842fb4257c49427d02da1a14e09 + checksum: 10/ae179355401c64423d39946eda22c5f7f74c94ce61c21505024d4d82c33853ec40bc9b370f75e4a7750b0524aba4d95a43fcc328d8d14684dc2abb41ba529de8 languageName: node linkType: hard "@types/react@npm:^18.2.38": - version: 18.3.18 - resolution: "@types/react@npm:18.3.18" + version: 18.3.20 + resolution: "@types/react@npm:18.3.20" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10/7fdd8b853e0d291d4138133f93f8d5c333da918e5804afcea61a923aab4bdfc9bb15eb21a5640959b452972b8715ddf10ffb12b3bd071898b9e37738636463f2 + checksum: 10/020c51e63b60862e6d772f0cdea0b9441182eedab6289dabd8add0708ded62003834c4e7c6f23a1ccd3ca9486b46296057c3f881c34261a0483765351f8d0bc3 languageName: node linkType: hard "@types/semver@npm:^7.5.0": - version: 7.5.8 - resolution: "@types/semver@npm:7.5.8" - checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178 + version: 7.7.0 + resolution: "@types/semver@npm:7.7.0" + checksum: 10/ee4514c6c852b1c38f951239db02f9edeea39f5310fad9396a00b51efa2a2d96b3dfca1ae84c88181ea5b7157c57d32d7ef94edacee36fbf975546396b85ba5b languageName: node linkType: hard @@ -924,64 +938,91 @@ __metadata: languageName: node linkType: hard -"@vitest/expect@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/expect@npm:1.6.1" +"@vitest/expect@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/expect@npm:3.1.2" + dependencies: + "@vitest/spy": "npm:3.1.2" + "@vitest/utils": "npm:3.1.2" + chai: "npm:^5.2.0" + tinyrainbow: "npm:^2.0.0" + checksum: 10/3c414e376154c8095f40efe409bb5f2c9380ba05a15b20552ee2e29f73197ab73068177e3da298ac135ef72673d1ea92090c466c78443ee69a7438bc8ab65f4f + languageName: node + linkType: hard + +"@vitest/mocker@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/mocker@npm:3.1.2" + dependencies: + "@vitest/spy": "npm:3.1.2" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^0.30.17" + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10/e6d730400daa7a97fb277159733df1366a932b5b06ac83d72e094e5383191c2597b4a5ae3538b28de6112b9e5d314cb50b44e031e79522f43f3dfc8ab022a584 + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:3.1.2, @vitest/pretty-format@npm:^3.1.2": + version: 3.1.2 + resolution: "@vitest/pretty-format@npm:3.1.2" dependencies: - "@vitest/spy": "npm:1.6.1" - "@vitest/utils": "npm:1.6.1" - chai: "npm:^4.3.10" - checksum: 10/8aa366cc629bba4170eadebf092de9f64b46592fde9455b070cb7616dcba54f03d479e5844da0ddadecbc19a4f781a0b0d72ab2275cfccca54fd51398ac1b5d5 + tinyrainbow: "npm:^2.0.0" + checksum: 10/454d0a8c250dbe52f7ec9dab4968e7c769fa10c8318eb5c54cb4b6d5b524772c04856e1990279f2c6e76705ffa107fddcbc1973560ed3b88167c231ccfeada16 languageName: node linkType: hard -"@vitest/runner@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/runner@npm:1.6.1" +"@vitest/runner@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/runner@npm:3.1.2" dependencies: - "@vitest/utils": "npm:1.6.1" - p-limit: "npm:^5.0.0" - pathe: "npm:^1.1.1" - checksum: 10/b3ee2cb7b80108c48505f71e291b7a70c819dc4c704c77d44beb722d641c5ef8e6f623e95a0259a3d0e8178d1b3559f426d03f13a3500420d1c2b8802e0128c4 + "@vitest/utils": "npm:3.1.2" + pathe: "npm:^2.0.3" + checksum: 10/b09c1ff3a556f318585307e6bb8954d219d0d35d1e17708fdd5d5ae1a230e6f29eba4f37a86faa71192f72406bb96b576c1b620d49d686def87bc5dcb8bf5737 languageName: node linkType: hard -"@vitest/snapshot@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/snapshot@npm:1.6.1" +"@vitest/snapshot@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/snapshot@npm:3.1.2" dependencies: - magic-string: "npm:^0.30.5" - pathe: "npm:^1.1.1" - pretty-format: "npm:^29.7.0" - checksum: 10/f78876503ac850ac3f0a0766133cd020d83c1e665711d4e4370f5f408051b8da7a6294882c549b00a90f03c4ca25b7c41893514a7d5f9f336e6a47ad533b4cb1 + "@vitest/pretty-format": "npm:3.1.2" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + checksum: 10/dda969b697bdcd8616f17e98c74ad5e95a5f3c2284140aa72390ce668db34e70936ee0b8ebe89adb2e0dea332500689d54c8ff03f8adf1e00be70639ec9032bf languageName: node linkType: hard -"@vitest/spy@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/spy@npm:1.6.1" +"@vitest/spy@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/spy@npm:3.1.2" dependencies: - tinyspy: "npm:^2.2.0" - checksum: 10/55076c8dad8585c4d3923ec1e948e97746150d9d259a7b6045d8dd0e22babc631b22c31882c976c25b68cfbaf11d9d47fe0a77e68c3f1b8973b90c6b835becdb + tinyspy: "npm:^3.0.2" + checksum: 10/c2c638368fa4130f903901fdf4e86da6f90d5d6a8cf7ce880cdd24768a1f8e6b726ea3428501c97e00c34ac2e8e39ac09b3a03606dffd8081559e0a35c892ddc languageName: node linkType: hard -"@vitest/utils@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/utils@npm:1.6.1" +"@vitest/utils@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/utils@npm:3.1.2" dependencies: - diff-sequences: "npm:^29.6.3" - estree-walker: "npm:^3.0.3" - loupe: "npm:^2.3.7" - pretty-format: "npm:^29.7.0" - checksum: 10/2aa8718c5e0705f28a8e94ac00055a48789b1badda79d3578d21241557195816508677ecd5f41fe355edb204e6f817124f059c4806102e040cc8890d8691ae9a + "@vitest/pretty-format": "npm:3.1.2" + loupe: "npm:^3.1.3" + tinyrainbow: "npm:^2.0.0" + checksum: 10/221faaaf6c69ef24eacdcf68581c833cb99bf3e5125945b5dec928af7ef1af4359aa520b90c42413a128b308037bf3217d8c41a41f44ca4aee3ac44e3f0d56b5 languageName: node linkType: hard "abbrev@npm:^3.0.0": - version: 3.0.0 - resolution: "abbrev@npm:3.0.0" - checksum: 10/2ceee14efdeda42ef7355178c1069499f183546ff7112b3efe79c1edef09d20ad9c17939752215fb8f7fcf48d10e6a7c0aa00136dc9cf4d293d963718bb1d200 + version: 3.0.1 + resolution: "abbrev@npm:3.0.1" + checksum: 10/ebd2c149dda6f543b66ce3779ea612151bb3aa9d0824f169773ee9876f1ca5a4e0adbcccc7eed048c04da7998e1825e2aa76fcca92d9e67dea50ac2b0a58dc2e languageName: node linkType: hard @@ -994,16 +1035,7 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.3.2": - version: 8.3.4 - resolution: "acorn-walk@npm:8.3.4" - dependencies: - acorn: "npm:^8.11.0" - checksum: 10/871386764e1451c637bb8ab9f76f4995d408057e9909be6fb5ad68537ae3375d85e6a6f170b98989f44ab3ff6c74ad120bc2779a3d577606e7a0cd2b4efcaf77 - languageName: node - linkType: hard - -"acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.9.0": +"acorn@npm:^8.9.0": version: 8.14.1 resolution: "acorn@npm:8.14.1" bin: @@ -1188,10 +1220,10 @@ __metadata: languageName: node linkType: hard -"assertion-error@npm:^1.1.0": - version: 1.1.0 - resolution: "assertion-error@npm:1.1.0" - checksum: 10/fd9429d3a3d4fd61782eb3962ae76b6d08aa7383123fca0596020013b3ebd6647891a85b05ce821c47d1471ed1271f00b0545cf6a4326cf2fc91efcc3b0fbecf +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: 10/a0789dd882211b87116e81e2648ccb7f60340b34f19877dd020b39ebb4714e475eb943e14ba3e22201c221ef6645b7bfe10297e76b6ac95b48a9898c1211ce66 languageName: node linkType: hard @@ -1339,18 +1371,16 @@ __metadata: languageName: node linkType: hard -"chai@npm:^4.3.10": - version: 4.5.0 - resolution: "chai@npm:4.5.0" +"chai@npm:^5.2.0": + version: 5.2.0 + resolution: "chai@npm:5.2.0" dependencies: - assertion-error: "npm:^1.1.0" - check-error: "npm:^1.0.3" - deep-eql: "npm:^4.1.3" - get-func-name: "npm:^2.0.2" - loupe: "npm:^2.3.6" - pathval: "npm:^1.1.1" - type-detect: "npm:^4.1.0" - checksum: 10/cde341aee15b0a51559c7cfc20788dcfb4d586a498cfb93b937bb568fd45c777b73b1461274be6092b6bf868adb4e3a63f3fec13c89f7d8fb194f84c6fa42d5f + assertion-error: "npm:^2.0.1" + check-error: "npm:^2.1.1" + deep-eql: "npm:^5.0.1" + loupe: "npm:^3.1.0" + pathval: "npm:^2.0.0" + checksum: 10/2ce03671c159c6a567bf1912756daabdbb7c075f3c0078f1b59d61da8d276936367ee696dfe093b49e1479d9ba93a6074c8e55d49791dddd8061728cdcad249e languageName: node linkType: hard @@ -1364,12 +1394,10 @@ __metadata: languageName: node linkType: hard -"check-error@npm:^1.0.3": - version: 1.0.3 - resolution: "check-error@npm:1.0.3" - dependencies: - get-func-name: "npm:^2.0.2" - checksum: 10/e2131025cf059b21080f4813e55b3c480419256914601750b0fee3bd9b2b8315b531e551ef12560419b8b6d92a3636511322752b1ce905703239e7cc451b6399 +"check-error@npm:^2.1.1": + version: 2.1.1 + resolution: "check-error@npm:2.1.1" + checksum: 10/d785ed17b1d4a4796b6e75c765a9a290098cf52ff9728ce0756e8ffd4293d2e419dd30c67200aee34202463b474306913f2fcfaf1890641026d9fc6966fea27a languageName: node linkType: hard @@ -1439,21 +1467,14 @@ __metadata: languageName: node linkType: hard -"confbox@npm:^0.1.8": - version: 0.1.8 - resolution: "confbox@npm:0.1.8" - checksum: 10/4ebcfb1c6a3b25276734ec5722e88768eb61fc02f98e11960b845c5c62bc27fd05f493d2a8244d9675b24ef95afe4c0d511cdcad02c72f5eeea463cc26687999 - languageName: node - linkType: hard - "consola@npm:^3.4.0": - version: 3.4.0 - resolution: "consola@npm:3.4.0" - checksum: 10/99d4a8131f4cc42ff6bb8e4fd8c9dbd428d6b949f3ec25d9d24892a7b0603b0aabeee8213e13ad74439b5078fdb204f9377bcdd401949c33fff672d91f05c4ec + version: 3.4.2 + resolution: "consola@npm:3.4.2" + checksum: 10/32192c9f50d7cac27c5d7c4ecd3ff3679aea863e6bf5bd6a9cc2b05d1cd78addf5dae71df08c54330c142be8e7fbd46f051030129b57c6aacdd771efe409c4b2 languageName: node linkType: hard -"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -1475,12 +1496,12 @@ __metadata: linkType: hard "cssstyle@npm:^4.0.1": - version: 4.3.0 - resolution: "cssstyle@npm:4.3.0" + version: 4.3.1 + resolution: "cssstyle@npm:4.3.1" dependencies: - "@asamuzakjp/css-color": "npm:^3.1.1" + "@asamuzakjp/css-color": "npm:^3.1.2" rrweb-cssom: "npm:^0.8.0" - checksum: 10/81e0634b1905080a4f07a117a345c773f531c01cb6dd408077b46d03e2c5b5b5f0b88ab36eba5fb82ce35ef2c5ddb02a3fd57f99b54e7ab0bd06d8708c319080 + checksum: 10/e74b2636067c3fd912a16d8d979a7975e5a5c8b3ce9386298d75a82478bb6c8bc03b261b92575348f471b3eb7534d2594a0c4b47d6fc8c03605b2628dce992ff languageName: node linkType: hard @@ -1553,12 +1574,10 @@ __metadata: languageName: node linkType: hard -"deep-eql@npm:^4.1.3": - version: 4.1.4 - resolution: "deep-eql@npm:4.1.4" - dependencies: - type-detect: "npm:^4.0.0" - checksum: 10/f04f4d581f044a824a6322fe4f68fbee4d6780e93fc710cd9852cbc82bfc7010df00f0e05894b848abbe14dc3a25acac44f424e181ae64d12f2ab9d0a875a5ef +"deep-eql@npm:^5.0.1": + version: 5.0.2 + resolution: "deep-eql@npm:5.0.2" + checksum: 10/a529b81e2ef8821621d20a36959a0328873a3e49d393ad11f8efe8559f31239494c2eb889b80342808674c475802ba95b9d6c4c27641b9a029405104c1b59fcf languageName: node linkType: hard @@ -1624,13 +1643,6 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^29.6.3": - version: 29.6.3 - resolution: "diff-sequences@npm:29.6.3" - checksum: 10/179daf9d2f9af5c57ad66d97cb902a538bcf8ed64963fa7aa0c329b3de3665ce2eb6ffdc2f69f29d445fa4af2517e5e55e5b6e00c00a9ae4f43645f97f7078cb - languageName: node - linkType: hard - "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -1706,10 +1718,10 @@ __metadata: languageName: node linkType: hard -"entities@npm:^4.5.0": - version: 4.5.0 - resolution: "entities@npm:4.5.0" - checksum: 10/ede2a35c9bce1aeccd055a1b445d41c75a14a2bb1cd22e242f20cf04d236cdcd7f9c859eb83f76885327bfae0c25bf03303665ee1ce3d47c5927b98b0e3e3d48 +"entities@npm:^6.0.0": + version: 6.0.0 + resolution: "entities@npm:6.0.0" + checksum: 10/cf37a4aad887ba8573532346da1c78349dccd5b510a9bbddf92fe59b36b18a8b26fe619a862de4e7fd3b8addc6d5e0969261198bbeb690da87297011a61b7066 languageName: node linkType: hard @@ -1841,6 +1853,13 @@ __metadata: languageName: node linkType: hard +"es-module-lexer@npm:^1.6.0": + version: 1.7.0 + resolution: "es-module-lexer@npm:1.7.0" + checksum: 10/b6f3e576a3fed4d82b0d0ad4bbf6b3a5ad694d2e7ce8c4a069560da3db6399381eaba703616a182b16dde50ce998af64e07dcf49f2ae48153b9e07be3f107087 + languageName: node + linkType: hard + "es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": version: 1.1.1 resolution: "es-object-atoms@npm:1.1.1" @@ -1882,34 +1901,35 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:0.23.0": - version: 0.23.0 - resolution: "esbuild@npm:0.23.0" - dependencies: - "@esbuild/aix-ppc64": "npm:0.23.0" - "@esbuild/android-arm": "npm:0.23.0" - "@esbuild/android-arm64": "npm:0.23.0" - "@esbuild/android-x64": "npm:0.23.0" - "@esbuild/darwin-arm64": "npm:0.23.0" - "@esbuild/darwin-x64": "npm:0.23.0" - "@esbuild/freebsd-arm64": "npm:0.23.0" - "@esbuild/freebsd-x64": "npm:0.23.0" - "@esbuild/linux-arm": "npm:0.23.0" - "@esbuild/linux-arm64": "npm:0.23.0" - "@esbuild/linux-ia32": "npm:0.23.0" - "@esbuild/linux-loong64": "npm:0.23.0" - "@esbuild/linux-mips64el": "npm:0.23.0" - "@esbuild/linux-ppc64": "npm:0.23.0" - "@esbuild/linux-riscv64": "npm:0.23.0" - "@esbuild/linux-s390x": "npm:0.23.0" - "@esbuild/linux-x64": "npm:0.23.0" - "@esbuild/netbsd-x64": "npm:0.23.0" - "@esbuild/openbsd-arm64": "npm:0.23.0" - "@esbuild/openbsd-x64": "npm:0.23.0" - "@esbuild/sunos-x64": "npm:0.23.0" - "@esbuild/win32-arm64": "npm:0.23.0" - "@esbuild/win32-ia32": "npm:0.23.0" - "@esbuild/win32-x64": "npm:0.23.0" +"esbuild@npm:^0.25.0": + version: 0.25.3 + resolution: "esbuild@npm:0.25.3" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.3" + "@esbuild/android-arm": "npm:0.25.3" + "@esbuild/android-arm64": "npm:0.25.3" + "@esbuild/android-x64": "npm:0.25.3" + "@esbuild/darwin-arm64": "npm:0.25.3" + "@esbuild/darwin-x64": "npm:0.25.3" + "@esbuild/freebsd-arm64": "npm:0.25.3" + "@esbuild/freebsd-x64": "npm:0.25.3" + "@esbuild/linux-arm": "npm:0.25.3" + "@esbuild/linux-arm64": "npm:0.25.3" + "@esbuild/linux-ia32": "npm:0.25.3" + "@esbuild/linux-loong64": "npm:0.25.3" + "@esbuild/linux-mips64el": "npm:0.25.3" + "@esbuild/linux-ppc64": "npm:0.25.3" + "@esbuild/linux-riscv64": "npm:0.25.3" + "@esbuild/linux-s390x": "npm:0.25.3" + "@esbuild/linux-x64": "npm:0.25.3" + "@esbuild/netbsd-arm64": "npm:0.25.3" + "@esbuild/netbsd-x64": "npm:0.25.3" + "@esbuild/openbsd-arm64": "npm:0.25.3" + "@esbuild/openbsd-x64": "npm:0.25.3" + "@esbuild/sunos-x64": "npm:0.25.3" + "@esbuild/win32-arm64": "npm:0.25.3" + "@esbuild/win32-ia32": "npm:0.25.3" + "@esbuild/win32-x64": "npm:0.25.3" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -1945,6 +1965,8 @@ __metadata: optional: true "@esbuild/linux-x64": optional: true + "@esbuild/netbsd-arm64": + optional: true "@esbuild/netbsd-x64": optional: true "@esbuild/openbsd-arm64": @@ -1961,7 +1983,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/d3d91bf9ca73ba33966fc54cabb321eca770a5e2ff5b34d67e4235c94560cfd881803e39fcaa31d842579d10600da5201c5f597f8438679f6db856f75ded7124 + checksum: 10/f1ff72289938330312926421f90eea442025cbbac295a7a2e8cfc2abbd9e3a8bc1502883468b0487e4020f1369e4726c851a2fa4b65a7c71331940072c3a1808 languageName: node linkType: hard @@ -1980,8 +2002,8 @@ __metadata: linkType: hard "eslint-plugin-react@npm:^7.26.1": - version: 7.37.4 - resolution: "eslint-plugin-react@npm:7.37.4" + version: 7.37.5 + resolution: "eslint-plugin-react@npm:7.37.5" dependencies: array-includes: "npm:^3.1.8" array.prototype.findlast: "npm:^1.2.5" @@ -1993,7 +2015,7 @@ __metadata: hasown: "npm:^2.0.2" jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.8" + object.entries: "npm:^1.1.9" object.fromentries: "npm:^2.0.8" object.values: "npm:^1.2.1" prop-types: "npm:^15.8.1" @@ -2003,7 +2025,7 @@ __metadata: string.prototype.repeat: "npm:^1.0.0" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - checksum: 10/c538c10665c87cb90a0bcc4efe53a758570db10997d079d31474a9760116ef5584648fa22403d889ca672df8071bda10b40434ea0499e5ee8360bc5c8aba1679 + checksum: 10/ee1bd4e0ec64f29109d5a625bb703d179c82e0159c86c3f1b52fc1209d2994625a137dae303c333fb308a2e38315e44066d5204998177e31974382f9fda25d5c languageName: node linkType: hard @@ -2133,23 +2155,6 @@ __metadata: languageName: node linkType: hard -"execa@npm:^8.0.1": - version: 8.0.1 - resolution: "execa@npm:8.0.1" - dependencies: - cross-spawn: "npm:^7.0.3" - get-stream: "npm:^8.0.1" - human-signals: "npm:^5.0.0" - is-stream: "npm:^3.0.0" - merge-stream: "npm:^2.0.0" - npm-run-path: "npm:^5.1.0" - onetime: "npm:^6.0.0" - signal-exit: "npm:^4.1.0" - strip-final-newline: "npm:^3.0.0" - checksum: 10/d2ab5fe1e2bb92b9788864d0713f1fce9a07c4594e272c0c97bc18c90569897ab262e4ea58d27a694d288227a2e24f16f5e2575b44224ad9983b799dc7f1098d - languageName: node - linkType: hard - "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -2157,6 +2162,13 @@ __metadata: languageName: node linkType: hard +"expect-type@npm:^1.2.1": + version: 1.2.1 + resolution: "expect-type@npm:1.2.1" + checksum: 10/d121d90f4f3f705ca0b656e36f28c0ba91483d0cddf2876e64e23c3dea2f2d5853e9c0c9a4e90eb4b3e4663bf09c2c02e9729c339dcd308c70b2107188e6b286 + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -2207,15 +2219,15 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.4.3": - version: 6.4.3 - resolution: "fdir@npm:6.4.3" +"fdir@npm:^6.4.4": + version: 6.4.4 + resolution: "fdir@npm:6.4.4" peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: picomatch: optional: true - checksum: 10/8e6d20f4590dc168de1374a9cadaa37e20ca6e0b822aa247c230e7ea1d9e9674a68cd816146435e4ecc98f9285091462ab7e5e56eebc9510931a1794e4db68b2 + checksum: 10/d0000d6b790059b35f4ed19acc8847a66452e0bc68b28766c929ffd523e5ec2083811fc8a545e4a1d4945ce70e887b3a610c145c681073b506143ae3076342ed languageName: node linkType: hard @@ -2366,13 +2378,6 @@ __metadata: languageName: node linkType: hard -"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2": - version: 2.0.2 - resolution: "get-func-name@npm:2.0.2" - checksum: 10/3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b - languageName: node - linkType: hard - "get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": version: 1.3.0 resolution: "get-intrinsic@npm:1.3.0" @@ -2401,13 +2406,6 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^8.0.1": - version: 8.0.1 - resolution: "get-stream@npm:8.0.1" - checksum: 10/dde5511e2e65a48e9af80fea64aff11b4921b14b6e874c6f8294c50975095af08f41bfb0b680c887f28b566dd6ec2cb2f960f9d36a323359be324ce98b766e9e - languageName: node - linkType: hard - "get-symbol-description@npm:^1.1.0": version: 1.1.0 resolution: "get-symbol-description@npm:1.1.0" @@ -2437,7 +2435,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -2614,13 +2612,6 @@ __metadata: languageName: node linkType: hard -"human-signals@npm:^5.0.0": - version: 5.0.0 - resolution: "human-signals@npm:5.0.0" - checksum: 10/30f8870d831cdcd2d6ec0486a7d35d49384996742052cee792854273fa9dd9e7d5db06bb7985d4953e337e10714e994e0302e90dc6848069171b05ec836d65b0 - languageName: node - linkType: hard - "iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -2906,13 +2897,6 @@ __metadata: languageName: node linkType: hard -"is-stream@npm:^3.0.0": - version: 3.0.0 - resolution: "is-stream@npm:3.0.0" - checksum: 10/172093fe99119ffd07611ab6d1bcccfe8bc4aa80d864b15f43e63e54b7abc71e779acd69afdb854c4e2a67fdc16ae710e370eda40088d1cfc956a50ed82d8f16 - languageName: node - linkType: hard - "is-string@npm:^1.0.7, is-string@npm:^1.1.1": version: 1.1.1 resolution: "is-string@npm:1.1.1" @@ -3031,13 +3015,6 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^9.0.1": - version: 9.0.1 - resolution: "js-tokens@npm:9.0.1" - checksum: 10/3288ba73bb2023adf59501979fb4890feb6669cc167b13771b226814fde96a1583de3989249880e3f4d674040d1815685db9a9880db9153307480d39dc760365 - languageName: node - linkType: hard - "js-yaml@npm:^4.1.0": version: 4.1.0 resolution: "js-yaml@npm:4.1.0" @@ -3182,16 +3159,6 @@ __metadata: languageName: node linkType: hard -"local-pkg@npm:^0.5.0": - version: 0.5.1 - resolution: "local-pkg@npm:0.5.1" - dependencies: - mlly: "npm:^1.7.3" - pkg-types: "npm:^1.2.1" - checksum: 10/d74aa7226b8cbbf4d7e587332ecb7d7e54e3380b834084eeec3fecfb072a3fc7db27fb0415cb3f4304d4b4055184eb0af43841000b76d33a32f8f3b49108dd20 - languageName: node - linkType: hard - "locate-path@npm:^6.0.0": version: 6.0.0 resolution: "locate-path@npm:6.0.0" @@ -3240,12 +3207,10 @@ __metadata: languageName: node linkType: hard -"loupe@npm:^2.3.6, loupe@npm:^2.3.7": - version: 2.3.7 - resolution: "loupe@npm:2.3.7" - dependencies: - get-func-name: "npm:^2.0.1" - checksum: 10/635c8f0914c2ce7ecfe4e239fbaf0ce1d2c00e4246fafcc4ed000bfdb1b8f89d05db1a220054175cca631ebf3894872a26fffba0124477fcb562f78762848fb1 +"loupe@npm:^3.1.0, loupe@npm:^3.1.3": + version: 3.1.3 + resolution: "loupe@npm:3.1.3" + checksum: 10/9e98c34daf0eba48ccc603595e51f2ae002110982d84879cf78c51de2c632f0c571dfe82ce4210af60c32203d06b443465c269bda925076fe6d9b612cc65c321 languageName: node linkType: hard @@ -3265,7 +3230,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.5": +"magic-string@npm:^0.30.17": version: 0.30.17 resolution: "magic-string@npm:0.30.17" dependencies: @@ -3314,13 +3279,6 @@ __metadata: languageName: node linkType: hard -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 10/6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 - languageName: node - linkType: hard - "merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" @@ -3361,13 +3319,6 @@ __metadata: languageName: node linkType: hard -"mimic-fn@npm:^4.0.0": - version: 4.0.0 - resolution: "mimic-fn@npm:4.0.0" - checksum: 10/995dcece15ee29aa16e188de6633d43a3db4611bcf93620e7e62109ec41c79c0f34277165b8ce5e361205049766e371851264c21ac64ca35499acb5421c2ba56 - languageName: node - linkType: hard - "minimatch@npm:9.0.3": version: 9.0.3 resolution: "minimatch@npm:9.0.3" @@ -3463,12 +3414,11 @@ __metadata: linkType: hard "minizlib@npm:^3.0.1": - version: 3.0.1 - resolution: "minizlib@npm:3.0.1" + version: 3.0.2 + resolution: "minizlib@npm:3.0.2" dependencies: - minipass: "npm:^7.0.4" - rimraf: "npm:^5.0.5" - checksum: 10/622cb85f51e5c206a080a62d20db0d7b4066f308cb6ce82a9644da112367c3416ae7062017e631eb7ac8588191cfa4a9a279b8651c399265202b298e98c4acef + minipass: "npm:^7.1.2" + checksum: 10/c075bed1594f68dcc8c35122333520112daefd4d070e5d0a228bd4cf5580e9eed3981b96c0ae1d62488e204e80fd27b2b9d0068ca9a5ef3993e9565faf63ca41 languageName: node linkType: hard @@ -3481,18 +3431,6 @@ __metadata: languageName: node linkType: hard -"mlly@npm:^1.7.3, mlly@npm:^1.7.4": - version: 1.7.4 - resolution: "mlly@npm:1.7.4" - dependencies: - acorn: "npm:^8.14.0" - pathe: "npm:^2.0.1" - pkg-types: "npm:^1.3.0" - ufo: "npm:^1.5.4" - checksum: 10/1b36163d38c2331f8ae480e6a11da3d15927a2148d729fcd9df6d0059ca74869aa693931bd1f762f82eb534b84c921bdfbc036eb0e4da4faeb55f1349d254f35 - languageName: node - linkType: hard - "ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" @@ -3512,11 +3450,11 @@ __metadata: linkType: hard "nanoid@npm:^3.3.8": - version: 3.3.9 - resolution: "nanoid@npm:3.3.9" + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" bin: nanoid: bin/nanoid.cjs - checksum: 10/80ec0f2f7fe0f472f459fbeab6afd88f6739e3da94cf2c2307bc83ef0203ec3b72e6113a9e3196ac4be79540440184136ee96e77c10a965e37d8347f43b265fa + checksum: 10/73b5afe5975a307aaa3c95dfe3334c52cdf9ae71518176895229b8d65ab0d1c0417dd081426134eb7571c055720428ea5d57c645138161e7d10df80815527c48 languageName: node linkType: hard @@ -3542,22 +3480,22 @@ __metadata: linkType: hard "node-gyp@npm:latest": - version: 11.1.0 - resolution: "node-gyp@npm:11.1.0" + version: 11.2.0 + resolution: "node-gyp@npm:11.2.0" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" graceful-fs: "npm:^4.2.6" make-fetch-happen: "npm:^14.0.3" nopt: "npm:^8.0.0" proc-log: "npm:^5.0.0" semver: "npm:^7.3.5" tar: "npm:^7.4.3" + tinyglobby: "npm:^0.2.12" which: "npm:^5.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10/3314ebfeb99dbcdf9e8c810df1ee52294045399873d4ab1e6740608c4fbe63adaf6580c0610b23c6eda125e298536553f5bb6fb0df714016a5c721ed31095e42 + checksum: 10/806fd8e3adc9157e17bf0d4a2c899cf6b98a0bbe9f453f630094ce791866271f6cddcaf2133e6513715d934fcba2014d287c7053d5d7934937b3a34d5a3d84ad languageName: node linkType: hard @@ -3572,15 +3510,6 @@ __metadata: languageName: node linkType: hard -"npm-run-path@npm:^5.1.0": - version: 5.3.0 - resolution: "npm-run-path@npm:5.3.0" - dependencies: - path-key: "npm:^4.0.0" - checksum: 10/ae8e7a89da9594fb9c308f6555c73f618152340dcaae423e5fb3620026fefbec463618a8b761920382d666fa7a2d8d240b6fe320e8a6cdd54dc3687e2b659d25 - languageName: node - linkType: hard - "object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -3626,14 +3555,15 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.8": - version: 1.1.8 - resolution: "object.entries@npm:1.1.8" +"object.entries@npm:^1.1.9": + version: 1.1.9 + resolution: "object.entries@npm:1.1.9" dependencies: - call-bind: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10/2301918fbd1ee697cf6ff7cd94f060c738c0a7d92b22fd24c7c250e9b593642c9707ad2c44d339303c1439c5967d8964251cdfc855f7f6ec55db2dd79e8dc2a7 + es-object-atoms: "npm:^1.1.1" + checksum: 10/24163ab1e1e013796693fc5f5d349e8b3ac0b6a34a7edb6c17d3dd45c6a8854145780c57d302a82512c1582f63720f4b4779d6c1cfba12cbb1420b978802d8a3 languageName: node linkType: hard @@ -3670,15 +3600,6 @@ __metadata: languageName: node linkType: hard -"onetime@npm:^6.0.0": - version: 6.0.0 - resolution: "onetime@npm:6.0.0" - dependencies: - mimic-fn: "npm:^4.0.0" - checksum: 10/0846ce78e440841335d4e9182ef69d5762e9f38aa7499b19f42ea1c4cd40f0b4446094c455c713f9adac3f4ae86f613bb5e30c99e52652764d06a89f709b3788 - languageName: node - linkType: hard - "optionator@npm:^0.9.3": version: 0.9.4 resolution: "optionator@npm:0.9.4" @@ -3713,15 +3634,6 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^5.0.0": - version: 5.0.0 - resolution: "p-limit@npm:5.0.0" - dependencies: - yocto-queue: "npm:^1.0.0" - checksum: 10/87bf5837dee6942f0dbeff318436179931d9a97848d1b07dbd86140a477a5d2e6b90d9701b210b4e21fe7beaea2979dfde366e4f576fa644a59bd4d6a6371da7 - languageName: node - linkType: hard - "p-locate@npm:^5.0.0": version: 5.0.0 resolution: "p-locate@npm:5.0.0" @@ -3755,11 +3667,11 @@ __metadata: linkType: hard "parse5@npm:^7.1.2": - version: 7.2.1 - resolution: "parse5@npm:7.2.1" + version: 7.3.0 + resolution: "parse5@npm:7.3.0" dependencies: - entities: "npm:^4.5.0" - checksum: 10/fd1a8ad1540d871e1ad6ca9bf5b67e30280886f1ce4a28052c0cb885723aa984d8cb1ec3da998349a6146960c8a84aa87b1a42600eb3b94495c7303476f2f88e + entities: "npm:^6.0.0" + checksum: 10/b0e48be20b820c655b138b86fa6fb3a790de6c891aa2aba536524f8027b4dca4fe538f11a0e5cf2f6f847d120dbb9e4822dcaeb933ff1e10850a2ef0154d1d88 languageName: node linkType: hard @@ -3784,13 +3696,6 @@ __metadata: languageName: node linkType: hard -"path-key@npm:^4.0.0": - version: 4.0.0 - resolution: "path-key@npm:4.0.0" - checksum: 10/8e6c314ae6d16b83e93032c61020129f6f4484590a777eed709c4a01b50e498822b00f76ceaf94bc64dbd90b327df56ceadce27da3d83393790f1219e07721d7 - languageName: node - linkType: hard - "path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" @@ -3815,24 +3720,17 @@ __metadata: languageName: node linkType: hard -"pathe@npm:^1.1.1": - version: 1.1.2 - resolution: "pathe@npm:1.1.2" - checksum: 10/f201d796351bf7433d147b92c20eb154a4e0ea83512017bf4ec4e492a5d6e738fb45798be4259a61aa81270179fce11026f6ff0d3fa04173041de044defe9d80 - languageName: node - linkType: hard - -"pathe@npm:^2.0.1": +"pathe@npm:^2.0.3": version: 2.0.3 resolution: "pathe@npm:2.0.3" checksum: 10/01e9a69928f39087d96e1751ce7d6d50da8c39abf9a12e0ac2389c42c83bc76f78c45a475bd9026a02e6a6f79be63acc75667df855862fe567d99a00a540d23d languageName: node linkType: hard -"pathval@npm:^1.1.1": - version: 1.1.1 - resolution: "pathval@npm:1.1.1" - checksum: 10/b50a4751068aa3a5428f5a0b480deecedc6f537666a3630a0c2ae2d5e7c0f4bf0ee77b48404441ec1220bef0c91625e6030b3d3cf5a32ab0d9764018d1d9dbb6 +"pathval@npm:^2.0.0": + version: 2.0.0 + resolution: "pathval@npm:2.0.0" + checksum: 10/b91575bf9cdf01757afd7b5e521eb8a0b874a49bc972d08e0047cfea0cd3c019f5614521d4bc83d2855e3fcc331db6817dfd533dd8f3d90b16bc76fad2450fc1 languageName: node linkType: hard @@ -3858,20 +3756,9 @@ __metadata: linkType: hard "pirates@npm:^4.0.1": - version: 4.0.6 - resolution: "pirates@npm:4.0.6" - checksum: 10/d02dda76f4fec1cbdf395c36c11cf26f76a644f9f9a1bfa84d3167d0d3154d5289aacc72677aa20d599bb4a6937a471de1b65c995e2aea2d8687cbcd7e43ea5f - languageName: node - linkType: hard - -"pkg-types@npm:^1.2.1, pkg-types@npm:^1.3.0": - version: 1.3.1 - resolution: "pkg-types@npm:1.3.1" - dependencies: - confbox: "npm:^0.1.8" - mlly: "npm:^1.7.4" - pathe: "npm:^2.0.1" - checksum: 10/6d491f2244597b24fb59a50e3c258f27da3839555d2a4e112b31bcf536e9359fc4edc98639cd74d2cf16fcd4269e5a09d99fc05d89e2acc896a2f027c2f6ec44 + version: 4.0.7 + resolution: "pirates@npm:4.0.7" + checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 languageName: node linkType: hard @@ -3905,7 +3792,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.43": +"postcss@npm:^8.5.3": version: 8.5.3 resolution: "postcss@npm:8.5.3" dependencies: @@ -3943,17 +3830,6 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.7.0": - version: 29.7.0 - resolution: "pretty-format@npm:29.7.0" - dependencies: - "@jest/schemas": "npm:^29.6.3" - ansi-styles: "npm:^5.0.0" - react-is: "npm:^18.0.0" - checksum: 10/dea96bc83c83cd91b2bfc55757b6b2747edcaac45b568e46de29deee80742f17bc76fe8898135a70d904f4928eafd8bb693cd1da4896e8bdd3c5e82cadf1d2bb - languageName: node - linkType: hard - "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -4038,13 +3914,6 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^18.0.0": - version: 18.3.1 - resolution: "react-is@npm:18.3.1" - checksum: 10/d5f60c87d285af24b1e1e7eaeb123ec256c3c8bdea7061ab3932e3e14685708221bf234ec50b21e10dd07f008f1b966a2730a0ce4ff67905b3872ff2042aec22 - languageName: node - linkType: hard - "react-redux@npm:^9.0.4": version: 9.2.0 resolution: "react-redux@npm:9.2.0" @@ -4195,6 +4064,7 @@ __metadata: "@reduxjs/toolkit": "npm:^2.0.1" "@testing-library/react": "npm:^14.1.2" "@types/lodash": "npm:^4.14.175" + "@types/node": "npm:^22.15.2" "@types/react": "npm:^18.2.38" "@types/react-dom": "npm:^18.2.17" "@types/shelljs": "npm:^0.8.11" @@ -4219,7 +4089,7 @@ __metadata: shelljs: "npm:^0.8.5" tsup: "npm:^8.2.4" typescript: "npm:^5.8.2" - vitest: "npm:^1.6.0" + vitest: "npm:^3.1.2" languageName: unknown linkType: soft @@ -4314,41 +4184,31 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^5.0.5": - version: 5.0.10 - resolution: "rimraf@npm:5.0.10" - dependencies: - glob: "npm:^10.3.7" - bin: - rimraf: dist/esm/bin.mjs - checksum: 10/f3b8ce81eecbde4628b07bdf9e2fa8b684e0caea4999acb1e3b0402c695cd41f28cd075609a808e61ce2672f528ca079f675ab1d8e8d5f86d56643a03e0b8d2e - languageName: node - linkType: hard - -"rollup@npm:^4.20.0, rollup@npm:^4.34.8": - version: 4.35.0 - resolution: "rollup@npm:4.35.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.35.0" - "@rollup/rollup-android-arm64": "npm:4.35.0" - "@rollup/rollup-darwin-arm64": "npm:4.35.0" - "@rollup/rollup-darwin-x64": "npm:4.35.0" - "@rollup/rollup-freebsd-arm64": "npm:4.35.0" - "@rollup/rollup-freebsd-x64": "npm:4.35.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.35.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.35.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.35.0" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.35.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.35.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-x64-musl": "npm:4.35.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.35.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.35.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.35.0" - "@types/estree": "npm:1.0.6" +"rollup@npm:^4.34.8, rollup@npm:^4.34.9": + version: 4.40.0 + resolution: "rollup@npm:4.40.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.40.0" + "@rollup/rollup-android-arm64": "npm:4.40.0" + "@rollup/rollup-darwin-arm64": "npm:4.40.0" + "@rollup/rollup-darwin-x64": "npm:4.40.0" + "@rollup/rollup-freebsd-arm64": "npm:4.40.0" + "@rollup/rollup-freebsd-x64": "npm:4.40.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.40.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.40.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.40.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.40.0" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.40.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.40.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.40.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.40.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.40.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.40.0" + "@rollup/rollup-linux-x64-musl": "npm:4.40.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.40.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.40.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.40.0" + "@types/estree": "npm:1.0.7" fsevents: "npm:~2.3.2" dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -4377,6 +4237,8 @@ __metadata: optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true "@rollup/rollup-linux-s390x-gnu": optional: true "@rollup/rollup-linux-x64-gnu": @@ -4393,7 +4255,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/1fd13b8cb874106727cc4241e7b09167b835247185f52a0ac0d4b302df6dd01feec32e53ee3fead757c0c033f8b15ae6f0e093854de1878ae9e5dee37ec52579 + checksum: 10/59976247cd855bc48b7192c82a6751bd04213e5a265109c652a6c43bde9056038c6399c0cf50ea3001edd5c11bb878a59e1055bb651b3bd6bbd0373c0345ed0c languageName: node linkType: hard @@ -4625,7 +4487,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": +"signal-exit@npm:^4.0.1": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f @@ -4715,10 +4577,10 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.5.0": - version: 3.8.1 - resolution: "std-env@npm:3.8.1" - checksum: 10/ee119570e2e449be86aa4972f119f9086a918307cc524f6e891b7a7c1327a5c970cf1b7d5898c881777845292a7e3380cf7d80ad34aee355d2c22ac5eb628542 +"std-env@npm:^3.9.0": + version: 3.9.0 + resolution: "std-env@npm:3.9.0" + checksum: 10/3044b2c54a74be4f460db56725571241ab3ac89a91f39c7709519bc90fa37148784bc4cd7d3a301aa735f43bd174496f263563f76703ce3e81370466ab7c235b languageName: node linkType: hard @@ -4850,13 +4712,6 @@ __metadata: languageName: node linkType: hard -"strip-final-newline@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-final-newline@npm:3.0.0" - checksum: 10/23ee263adfa2070cd0f23d1ac14e2ed2f000c9b44229aec9c799f1367ec001478469560abefd00c5c99ee6f0b31c137d53ec6029c53e9f32a93804e18c201050 - languageName: node - linkType: hard - "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -4864,15 +4719,6 @@ __metadata: languageName: node linkType: hard -"strip-literal@npm:^2.0.0": - version: 2.1.1 - resolution: "strip-literal@npm:2.1.1" - dependencies: - js-tokens: "npm:^9.0.1" - checksum: 10/b4a1c93b0fe7b3ed2d197547f1b3f7bc20bd2c156b7474e4dbf4c9c80d2c612a862b00454dc9afc96ab1ea4f5653a5d0b530af052710f7730de55240e8fab2dc - languageName: node - linkType: hard - "sucrase@npm:^3.35.0": version: 3.35.0 resolution: "sucrase@npm:3.35.0" @@ -4962,7 +4808,7 @@ __metadata: languageName: node linkType: hard -"tinybench@npm:^2.5.1": +"tinybench@npm:^2.9.0": version: 2.9.0 resolution: "tinybench@npm:2.9.0" checksum: 10/cfa1e1418e91289219501703c4693c70708c91ffb7f040fd318d24aef419fb5a43e0c0160df9471499191968b2451d8da7f8087b08c3133c251c40d24aced06c @@ -4976,27 +4822,34 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.11": - version: 0.2.12 - resolution: "tinyglobby@npm:0.2.12" +"tinyglobby@npm:^0.2.11, tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13": + version: 0.2.13 + resolution: "tinyglobby@npm:0.2.13" dependencies: - fdir: "npm:^6.4.3" + fdir: "npm:^6.4.4" picomatch: "npm:^4.0.2" - checksum: 10/4ad28701fa9118b32ef0e27f409e0a6c5741e8b02286d50425c1f6f71e6d6c6ded9dd5bbbbb714784b08623c4ec4d150151f1d3d996cfabe0495f908ab4f7002 + checksum: 10/b04557ee58ad2be5f2d2cbb4b441476436c92bb45ba2e1fc464d686b793392b305ed0bcb8b877429e9b5036bdd46770c161a08384c0720b6682b7cd6ac80e403 languageName: node linkType: hard -"tinypool@npm:^0.8.3": - version: 0.8.4 - resolution: "tinypool@npm:0.8.4" - checksum: 10/7365944c2532f240111443e7012be31a634faf1a02db08a91db3aa07361c26a374d0be00a0f2ea052c4bee39c107ba67f1f814c108d9d51dfc725c559c1a9c03 +"tinypool@npm:^1.0.2": + version: 1.0.2 + resolution: "tinypool@npm:1.0.2" + checksum: 10/6109322f14b3763f65c8fa49fddab72cd3edd96b82dd50e05e63de74867329ff5353bff4377281ec963213d9314f37f4a353e9ee34bbac85fd4c1e4a568d6076 languageName: node linkType: hard -"tinyspy@npm:^2.2.0": - version: 2.2.1 - resolution: "tinyspy@npm:2.2.1" - checksum: 10/170d6232e87f9044f537b50b406a38fbfd6f79a261cd12b92879947bd340939a833a678632ce4f5c4a6feab4477e9c21cd43faac3b90b68b77dd0536c4149736 +"tinyrainbow@npm:^2.0.0": + version: 2.0.0 + resolution: "tinyrainbow@npm:2.0.0" + checksum: 10/94d4e16246972614a5601eeb169ba94f1d49752426312d3cf8cc4f2cc663a2e354ffc653aa4de4eebccbf9eeebdd0caef52d1150271fdfde65d7ae7f3dcb9eb5 + languageName: node + linkType: hard + +"tinyspy@npm:^3.0.2": + version: 3.0.2 + resolution: "tinyspy@npm:3.0.2" + checksum: 10/5db671b2ff5cd309de650c8c4761ca945459d7204afb1776db9a04fb4efa28a75f08517a8620c01ee32a577748802231ad92f7d5b194dc003ee7f987a2a06337 languageName: node linkType: hard @@ -5030,12 +4883,12 @@ __metadata: languageName: node linkType: hard -"tr46@npm:^5.0.0": - version: 5.0.0 - resolution: "tr46@npm:5.0.0" +"tr46@npm:^5.1.0": + version: 5.1.1 + resolution: "tr46@npm:5.1.1" dependencies: punycode: "npm:^2.3.1" - checksum: 10/29155adb167d048d3c95d181f7cb5ac71948b4e8f3070ec455986e1f34634acae50ae02a3c8d448121c3afe35b76951cd46ed4c128fd80264280ca9502237a3e + checksum: 10/833a0e1044574da5790148fd17866d4ddaea89e022de50279967bcd6b28b4ce0d30d59eb3acf9702b60918975b3bad481400337e3a2e6326cffa5c77b874753d languageName: node linkType: hard @@ -5121,13 +4974,6 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:^4.0.0, type-detect@npm:^4.1.0": - version: 4.1.0 - resolution: "type-detect@npm:4.1.0" - checksum: 10/e363bf0352427a79301f26a7795a27718624c49c576965076624eb5495d87515030b207217845f7018093adcbe169b2d119bb9b7f1a31a92bfbb1ab9639ca8dd - languageName: node - linkType: hard - "type-fest@npm:^0.20.2": version: 0.20.2 resolution: "type-fest@npm:0.20.2" @@ -5189,29 +5035,22 @@ __metadata: linkType: hard "typescript@npm:^5.8.2": - version: 5.8.2 - resolution: "typescript@npm:5.8.2" + version: 5.8.3 + resolution: "typescript@npm:5.8.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/dbc2168a55d56771f4d581997be52bab5cbc09734fec976cfbaabd787e61fb4c6cf9125fd48c6f98054ce549c77ecedefc7f64252a830dd8e9c3381f61fbeb78 + checksum: 10/65c40944c51b513b0172c6710ee62e951b70af6f75d5a5da745cb7fab132c09ae27ffdf7838996e3ed603bb015dadd099006658046941bd0ba30340cc563ae92 languageName: node linkType: hard "typescript@patch:typescript@npm%3A^5.8.2#optional!builtin": - version: 5.8.2 - resolution: "typescript@patch:typescript@npm%3A5.8.2#optional!builtin::version=5.8.2&hash=8c6c40" + version: 5.8.3 + resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=8c6c40" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/6ae9b2c4d3254ec2eaee6f26ed997e19c02177a212422993209f81e87092b2bb0a4738085549c5b0164982a5609364c047c72aeb281f6c8d802cd0d1c6f0d353 - languageName: node - linkType: hard - -"ufo@npm:^1.5.4": - version: 1.5.4 - resolution: "ufo@npm:1.5.4" - checksum: 10/a885ed421e656aea6ca64e9727b8118a9488715460b6f1a0f0427118adfe2f2830fe7c1d5bd9c5c754a332e6807516551cd663ea67ce9ed6a4e3edc739916335 + checksum: 10/98470634034ec37fd9ea61cc82dcf9a27950d0117a4646146b767d085a2ec14b137aae9642a83d1c62732d7fdcdac19bb6288b0bb468a72f7a06ae4e1d2c72c9 languageName: node linkType: hard @@ -5227,10 +5066,10 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~6.20.0": - version: 6.20.0 - resolution: "undici-types@npm:6.20.0" - checksum: 10/583ac7bbf4ff69931d3985f4762cde2690bb607844c16a5e2fbb92ed312fe4fa1b365e953032d469fa28ba8b224e88a595f0b10a449332f83fa77c695e567dbe +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 10/ec8f41aa4359d50f9b59fa61fe3efce3477cc681908c8f84354d8567bb3701fafdddf36ef6bff307024d3feb42c837cf6f670314ba37fc8145e219560e473d14 languageName: node linkType: hard @@ -5279,11 +5118,11 @@ __metadata: linkType: hard "use-sync-external-store@npm:^1.4.0": - version: 1.4.0 - resolution: "use-sync-external-store@npm:1.4.0" + version: 1.5.0 + resolution: "use-sync-external-store@npm:1.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10/08bf581a8a2effaefc355e9d18ed025d436230f4cc973db2f593166df357cf63e47b9097b6e5089b594758bde322e1737754ad64905e030d70f8ff7ee671fd01 + checksum: 10/ddae7c4572511f7f641d6977bd0725340aa7dbeda8250418b54c1a57ec285083d96cf50d1a1acbd6cf729f7a87071b2302c6fbd29310432bf1b21a961a313279 languageName: node linkType: hard @@ -5294,44 +5133,52 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:1.6.1": - version: 1.6.1 - resolution: "vite-node@npm:1.6.1" +"vite-node@npm:3.1.2": + version: 3.1.2 + resolution: "vite-node@npm:3.1.2" dependencies: cac: "npm:^6.7.14" - debug: "npm:^4.3.4" - pathe: "npm:^1.1.1" - picocolors: "npm:^1.0.0" - vite: "npm:^5.0.0" + debug: "npm:^4.4.0" + es-module-lexer: "npm:^1.6.0" + pathe: "npm:^2.0.3" + vite: "npm:^5.0.0 || ^6.0.0" bin: vite-node: vite-node.mjs - checksum: 10/35f77a9efa38fae349e9c383780984deee185e0fdd107394ffe320586c9a896c59e9b098a9a9f96412adb293abf1a27671ca592b39013edadb9e0614aa817419 + checksum: 10/8af0465810c6f27200dc899792002320995f3d85c432aaa411bf7ff15580c0b93c4a5153d8a93c7af89b496a6e1a7979a7777984e37ebd7311851ea7572eaac7 languageName: node linkType: hard -"vite@npm:^5.0.0": - version: 5.4.14 - resolution: "vite@npm:5.4.14" +"vite@npm:^5.0.0 || ^6.0.0": + version: 6.3.3 + resolution: "vite@npm:6.3.3" dependencies: - esbuild: "npm:^0.21.3" + esbuild: "npm:^0.25.0" + fdir: "npm:^6.4.4" fsevents: "npm:~2.3.3" - postcss: "npm:^8.4.43" - rollup: "npm:^4.20.0" + picomatch: "npm:^4.0.2" + postcss: "npm:^8.5.3" + rollup: "npm:^4.34.9" + tinyglobby: "npm:^0.2.13" peerDependencies: - "@types/node": ^18.0.0 || >=20.0.0 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: ">=1.21.0" less: "*" lightningcss: ^1.21.0 sass: "*" sass-embedded: "*" stylus: "*" sugarss: "*" - terser: ^5.4.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 dependenciesMeta: fsevents: optional: true peerDependenciesMeta: "@types/node": optional: true + jiti: + optional: true less: optional: true lightningcss: @@ -5346,46 +5193,54 @@ __metadata: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true bin: vite: bin/vite.js - checksum: 10/ce382f4059eb6c939823b8f62163794752243755d84c71a4b73ad0f7d4d9f4c7a557a6ef4c78e0640f4bcf5ae5ec6b20c7ee4816419af3c81ba275f478b73468 + checksum: 10/442e518d9da847db80bd19a9792d1d9a106a31d18f74bfd06574776932dd0907f7205b99e34d455ba505a7dd9e57a807354633b90acd46a11db849a15ae26ad4 languageName: node linkType: hard -"vitest@npm:^1.6.0": - version: 1.6.1 - resolution: "vitest@npm:1.6.1" - dependencies: - "@vitest/expect": "npm:1.6.1" - "@vitest/runner": "npm:1.6.1" - "@vitest/snapshot": "npm:1.6.1" - "@vitest/spy": "npm:1.6.1" - "@vitest/utils": "npm:1.6.1" - acorn-walk: "npm:^8.3.2" - chai: "npm:^4.3.10" - debug: "npm:^4.3.4" - execa: "npm:^8.0.1" - local-pkg: "npm:^0.5.0" - magic-string: "npm:^0.30.5" - pathe: "npm:^1.1.1" - picocolors: "npm:^1.0.0" - std-env: "npm:^3.5.0" - strip-literal: "npm:^2.0.0" - tinybench: "npm:^2.5.1" - tinypool: "npm:^0.8.3" - vite: "npm:^5.0.0" - vite-node: "npm:1.6.1" - why-is-node-running: "npm:^2.2.2" +"vitest@npm:^3.1.2": + version: 3.1.2 + resolution: "vitest@npm:3.1.2" + dependencies: + "@vitest/expect": "npm:3.1.2" + "@vitest/mocker": "npm:3.1.2" + "@vitest/pretty-format": "npm:^3.1.2" + "@vitest/runner": "npm:3.1.2" + "@vitest/snapshot": "npm:3.1.2" + "@vitest/spy": "npm:3.1.2" + "@vitest/utils": "npm:3.1.2" + chai: "npm:^5.2.0" + debug: "npm:^4.4.0" + expect-type: "npm:^1.2.1" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + std-env: "npm:^3.9.0" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^0.3.2" + tinyglobby: "npm:^0.2.13" + tinypool: "npm:^1.0.2" + tinyrainbow: "npm:^2.0.0" + vite: "npm:^5.0.0 || ^6.0.0" + vite-node: "npm:3.1.2" + why-is-node-running: "npm:^2.3.0" peerDependencies: "@edge-runtime/vm": "*" - "@types/node": ^18.0.0 || >=20.0.0 - "@vitest/browser": 1.6.1 - "@vitest/ui": 1.6.1 + "@types/debug": ^4.1.12 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + "@vitest/browser": 3.1.2 + "@vitest/ui": 3.1.2 happy-dom: "*" jsdom: "*" peerDependenciesMeta: "@edge-runtime/vm": optional: true + "@types/debug": + optional: true "@types/node": optional: true "@vitest/browser": @@ -5398,7 +5253,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 10/50d551be2cf6621d3844c42924595007befd73e10e9406e0fa08f1239e2c012d08f85b0a70d8656a11364a6a58930600c35a5ee00d8445071f0ab0afcacd085a + checksum: 10/aa5638bf37b2811b01ad8ff0563cdec09202f7a28d9dbcb8eabb2e51cadefc57309cba4f5ff2bac4a72edda44055a844236fc4a09eb72127ef1bd34eb25d0808 languageName: node linkType: hard @@ -5442,12 +5297,12 @@ __metadata: linkType: hard "whatwg-url@npm:^14.0.0": - version: 14.1.1 - resolution: "whatwg-url@npm:14.1.1" + version: 14.2.0 + resolution: "whatwg-url@npm:14.2.0" dependencies: - tr46: "npm:^5.0.0" + tr46: "npm:^5.1.0" webidl-conversions: "npm:^7.0.0" - checksum: 10/803bede3ec6c8f14de0d84ac6032479646b5a2b08f5a7289366c3461caed9d7888d171e2846b59798869191037562c965235c2eed6ff2e266c05a2b4a6ce0160 + checksum: 10/f0a95b0601c64f417c471536a2d828b4c16fe37c13662483a32f02f183ed0f441616609b0663fb791e524e8cd56d9a86dd7366b1fc5356048ccb09b576495e7c languageName: node linkType: hard @@ -5545,7 +5400,7 @@ __metadata: languageName: node linkType: hard -"why-is-node-running@npm:^2.2.2": +"why-is-node-running@npm:^2.3.0": version: 2.3.0 resolution: "why-is-node-running@npm:2.3.0" dependencies: @@ -5671,10 +5526,3 @@ __metadata: checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard - -"yocto-queue@npm:^1.0.0": - version: 1.2.0 - resolution: "yocto-queue@npm:1.2.0" - checksum: 10/6154113e60285f75c9d59c65056ea3842d3d5c999a4c692568155dcc5b9c038850374eae1f04507090eeee8129b8110d9c7259d1aa9fe323957fd46892b655fc - languageName: node - linkType: hard