From 2c451fcb9037af1635403721708f74b2ed10bd70 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 08:32:23 -0600 Subject: [PATCH 01/60] Remove unnecessary `include` and `typecheck` from `vitest.config.mts` --- vitest.config.mts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/vitest.config.mts b/vitest.config.mts index b45318ec5..99ac2dbfd 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -1,7 +1,6 @@ -import { defineConfig } from 'vitest/config' - import path from 'node:path' import { fileURLToPath } from 'node:url' +import { defineConfig } from 'vitest/config' // No __dirname under Node ESM const __filename = fileURLToPath(import.meta.url) @@ -9,9 +8,7 @@ const __dirname = path.dirname(__filename) export default defineConfig({ test: { - typecheck: { tsconfig: 'type-tests/tsconfig.json' }, globals: true, - include: ['./test/**/*.(spec|test).[jt]s?(x)'], setupFiles: ['test/setup.vitest.ts'], alias: { reselect: path.join(__dirname, 'src/index.ts'), // @remap-prod-remove-line From 06145f6974382684f9665cdac0d5bffa8fc3e01f Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 08:34:55 -0600 Subject: [PATCH 02/60] Rename `test/tsconfig.json` to `tsconfig.test.json` --- test/tsconfig.json => tsconfig.test.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/tsconfig.json => tsconfig.test.json (100%) diff --git a/test/tsconfig.json b/tsconfig.test.json similarity index 100% rename from test/tsconfig.json rename to tsconfig.test.json From 48e7b81249d4b988785c13f710da671142814b7b Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 08:36:00 -0600 Subject: [PATCH 03/60] Revamp type tests config --- tsconfig.base.json | 33 +++++++++++++++++++++++++++++++++ tsconfig.build.json | 11 +++++++++++ tsconfig.json | 29 ++++++----------------------- tsconfig.test.json | 24 ++++-------------------- type-tests/tsconfig.json | 17 ----------------- typescript_test/tsconfig.json | 16 ---------------- 6 files changed, 54 insertions(+), 76 deletions(-) create mode 100644 tsconfig.base.json create mode 100644 tsconfig.build.json delete mode 100644 type-tests/tsconfig.json delete mode 100644 typescript_test/tsconfig.json 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 index 0d98c80c8..0995aae05 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -1,25 +1,9 @@ { - "extends": "../tsconfig.json", + // For type tests during CI. + "extends": "./tsconfig.base.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/*"] - } + "rootDir": "./" }, - "include": ["**/*.ts*"] + "include": ["type-tests"] } 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/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"] -} From 89baf667b5156d825d196c10d8cce04d5955362d Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 08:37:15 -0600 Subject: [PATCH 04/60] Update CI to include correct tsconfig --- .github/workflows/build-and-test-types.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test-types.yml b/.github/workflows/build-and-test-types.yml index 392338d23..cd4283f3e 100644 --- a/.github/workflows/build-and-test-types.yml +++ b/.github/workflows/build-and-test-types.yml @@ -84,7 +84,7 @@ jobs: # 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 + - run: sed -i -e /@remap-prod-remove-line/d tsconfig.base.json vitest.config.mts - name: Test types run: | From 409bf820161d56d4bcce4707648e4f043c9bac40 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 08:40:16 -0600 Subject: [PATCH 05/60] Fix `testTypes` import --- test/selectorUtils.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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', () => { From 5b8faeea8412922ad96b91f1a341b23c8fd6958c Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 09:42:20 -0600 Subject: [PATCH 06/60] Convert `assertType` usages to `.toEqualTypeOf` calls --- type-tests/argsMemoize.test-d.ts | 402 ++++++++++++++++++++----------- 1 file changed, 262 insertions(+), 140 deletions(-) diff --git a/type-tests/argsMemoize.test-d.ts b/type-tests/argsMemoize.test-d.ts index d7f2c51c1..47d90ecb6 100644 --- a/type-tests/argsMemoize.test-d.ts +++ b/type-tests/argsMemoize.test-d.ts @@ -354,10 +354,14 @@ describe('memoize and argsMemoize', () => { (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` + expectTypeOf(selectorMicroMemoize).parameter(0).not.toBeNever() + selectorMicroMemoize.cache selectorMicroMemoize.fn() selectorMicroMemoize.isMemoized @@ -373,27 +377,34 @@ describe('memoize and argsMemoize', () => { selectorMicroMemoize.memoizedResultFunc.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,9 +422,11 @@ 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. @@ -435,28 +448,40 @@ describe('memoize and argsMemoize', () => { // @ts-expect-error Prior to override, this field DID exist. selectorMicroMemoizeOverridden.memoizedResultFunc.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,9 +493,13 @@ 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. @@ -492,30 +521,48 @@ describe('memoize and argsMemoize', () => { // @ts-expect-error Prior to override, this field DID exist. selectorMicroMemoizeOverriddenArray.memoizedResultFunc.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( @@ -542,9 +589,15 @@ 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. @@ -565,33 +618,49 @@ describe('memoize and argsMemoize', () => { // `memoizedResultFunc.clearCache` is still an invalid field access. selectorMicroMemoizeOverrideArgsMemoizeOnly.memoizedResultFunc.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,9 +670,14 @@ 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 @@ -626,31 +700,49 @@ describe('memoize and argsMemoize', () => { selectorMicroMemoizeOverrideMemoizeOnly.memoizedResultFunc.clearCache() // Prior to override, this field did NOT exist. // 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` @@ -693,17 +785,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,26 +800,30 @@ 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.toMatchTypeOf< + [RootState] + >() + + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchTypeOf< + [number] + >() + + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchTypeOf< + [RootState, string] + >() + + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchTypeOf< + [RootState, number, number] + >() + // Checking existence of fields related to `argsMemoize` // Prior to override, this field did NOT exist. selectorDefaultParametric.cache @@ -757,29 +843,45 @@ describe('memoize and argsMemoize', () => { selectorDefaultParametric.memoizedResultFunc.clear() // 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,11 +898,15 @@ describe('memoize and argsMemoize', () => { (state: RootState) => state.todos, todos => todos.map(({ id }) => id) ) - assertType( + + expectTypeOf( selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault(state) - ) - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault() + ).items.toBeNumber() + + expectTypeOf(selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault) + .parameter(0) + .not.toBeNever() + selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.clearCache() // @ts-expect-error @@ -822,36 +928,52 @@ describe('memoize and argsMemoize', () => { // @ts-expect-error selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.memoizedResultFunc.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) From c5f8f03ce7a691e0ad3023a27a765cbe3272750f Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:01:35 -0600 Subject: [PATCH 07/60] Simplify type tests in `createStructuredSelector.withTypes.test-d.ts` --- ...eateStructuredSelector.withTypes.test-d.ts | 203 +++++++----------- 1 file changed, 79 insertions(+), 124 deletions(-) diff --git a/type-tests/createStructuredSelector.withTypes.test-d.ts b/type-tests/createStructuredSelector.withTypes.test-d.ts index 9bb5b1ff7..3c461dbce 100644 --- a/type-tests/createStructuredSelector.withTypes.test-d.ts +++ b/type-tests/createStructuredSelector.withTypes.test-d.ts @@ -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() @@ -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() + ) }) }) From b7819813a2d90a1e756311f6bc65824a5464fe59 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:06:09 -0600 Subject: [PATCH 08/60] Simplify the type tests in `createStructuredSelector.test-d.ts` --- type-tests/createStructuredSelector.test-d.ts | 90 +++++++------------ 1 file changed, 32 insertions(+), 58 deletions(-) diff --git a/type-tests/createStructuredSelector.test-d.ts b/type-tests/createStructuredSelector.test-d.ts index e7398f476..97a3be8df 100644 --- a/type-tests/createStructuredSelector.test-d.ts +++ b/type-tests/createStructuredSelector.test-d.ts @@ -43,12 +43,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 +60,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 +86,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 +123,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 +151,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,13 +185,9 @@ 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() @@ -248,26 +226,22 @@ 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() + ) }) }) From 2fb9b58b9b28c64651141f01f6bcb4613329cbf5 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:07:41 -0600 Subject: [PATCH 09/60] Simplify the type tests inside `createSelector.withTypes.test-d.ts` --- type-tests/createSelector.withTypes.test-d.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/type-tests/createSelector.withTypes.test-d.ts b/type-tests/createSelector.withTypes.test-d.ts index c3e00618e..aa517b6dd 100644 --- a/type-tests/createSelector.withTypes.test-d.ts +++ b/type-tests/createSelector.withTypes.test-d.ts @@ -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) } @@ -62,7 +62,7 @@ describe('createSelector.withTypes()', () => { // input selectors are provided as separate inline arguments. createAppSelector( state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, @@ -70,7 +70,7 @@ describe('createSelector.withTypes()', () => { // Known limitation: Parameter types are not inferred in this scenario expectTypeOf(todos).toBeAny() - expectTypeOf(todos).not.toEqualTypeOf(rootState.todos) + expectTypeOf(todos).not.toEqualTypeOf() // @ts-expect-error A typed `createSelector` currently only infers // the parameter types of the result function when @@ -85,12 +85,12 @@ describe('createSelector.withTypes()', () => { // input selectors are provided as separate inline arguments. createAppSelector( state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.todos }, state => { - expectTypeOf(state).toEqualTypeOf(rootState) + expectTypeOf(state).toEqualTypeOf(rootState) return state.alerts }, From 1681375f455ad1ff7b8debcd4874c4a7d2cee67a Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:27:06 -0600 Subject: [PATCH 10/60] Add more meaningful assertions to `deepNesting.test-d.ts` --- type-tests/deepNesting.test-d.ts | 129 +++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 23 deletions(-) diff --git a/type-tests/deepNesting.test-d.ts b/type-tests/deepNesting.test-d.ts index c4bdc2411..5f98ff407 100644 --- a/type-tests/deepNesting.test-d.ts +++ b/type-tests/deepNesting.test-d.ts @@ -1,3 +1,4 @@ +import type { Cache } from 'micro-memoize' import microMemoize from 'micro-memoize' import { createSelector, lruMemoize } from 'reselect' import { describe, test } from 'vitest' @@ -16,12 +17,13 @@ const state: RootState = { ] } +type AnyFunction = (...args: any[]) => any + describe('deep nesting', () => { test('Deep Nesting First And 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) const selector2 = createSelector(selector1, s => s) const selector3 = createSelector(selector2, s => s) @@ -34,9 +36,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 +55,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 +74,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 +123,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 +162,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 +198,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 +230,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 +249,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 +268,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', () => { From 233367afe493b98ebdeaefc1b694c07f7c4e2c55 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:30:29 -0600 Subject: [PATCH 11/60] Remove `expectType` and `expectExactType` --- typescript_test/typesTestUtils.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/typescript_test/typesTestUtils.ts b/typescript_test/typesTestUtils.ts index c27892f29..8703bb027 100644 --- a/typescript_test/typesTestUtils.ts +++ b/typescript_test/typesTestUtils.ts @@ -1,29 +1,5 @@ -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) => {} -} From 1feb5907de685c242c927d0be9b95ef13f42bab0 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:31:17 -0600 Subject: [PATCH 12/60] Remove `argsMemoize.typetest.ts` file --- typescript_test/argsMemoize.typetest.ts | 1160 ----------------------- 1 file changed, 1160 deletions(-) delete mode 100644 typescript_test/argsMemoize.typetest.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 - } - } - ) -} From ebc915a1250b8cee5520d24a93770ccbde1d066f Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:34:42 -0600 Subject: [PATCH 13/60] Replace `expectExactType` calls with `expectTypeOf().toEqualTypeOf()` --- typescript_test/test.ts | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/typescript_test/test.ts b/typescript_test/test.ts index 0795f2e70..2d7337080 100644 --- a/typescript_test/test.ts +++ b/typescript_test/test.ts @@ -20,17 +20,6 @@ import { 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 @@ -41,12 +30,6 @@ interface StateAB { b: number } -interface StateSub { - sub: { - a: number - } -} - // Test exporting export const testExportBasic = createSelector( (state: StateA) => state.a, @@ -860,7 +843,7 @@ function testTypedCreateStructuredSelector() { }) // Their types are the same. - expectExactType(selectorGenerics) + expectTypeOf(selectorGenerics).toEqualTypeOf(selectorGenerics1) } function testDynamicArrayArgument() { @@ -1611,7 +1594,8 @@ function issue554b() { type selectTestParams = Parameters const p1: selectTestParams = [{ counter1: 1, counter2: 2 }, 42] - expectExactType<[State, number?]>(p1) + + expectTypeOf(p1).toEqualTypeOf<[State, number?]>() const result = selectTest({ counter1: 1, counter2: 2 }, 42) } @@ -1724,15 +1708,21 @@ function testCreateStructuredSelectorNew() { multiArgsStructuredSelector.memoizedResultFunc.options multiArgsStructuredSelector(state, 2, true).selectedCompletedTodos - expectExactType(multiArgsStructuredSelector.argsMemoize) - expectExactType(multiArgsStructuredSelector.memoize) - expectExactType< + + expectTypeOf(multiArgsStructuredSelector.argsMemoize).toEqualTypeOf( + microMemoize + ) + + expectTypeOf(multiArgsStructuredSelector.memoize).toEqualTypeOf(microMemoize) + + expectTypeOf(multiArgsStructuredSelector.dependencies).toEqualTypeOf< [ (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) } From 448ff60db18e691bed7192f8adedd0cf7015c652 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 10:36:40 -0600 Subject: [PATCH 14/60] Remove duplicate tests for `typedStructuredSelectorCreator` --- typescript_test/test.ts | 50 ++--------------------------------------- 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/typescript_test/test.ts b/typescript_test/test.ts index 2d7337080..2a7ba5ffe 100644 --- a/typescript_test/test.ts +++ b/typescript_test/test.ts @@ -10,8 +10,7 @@ import { useSelector } from 'react-redux' import type { GetStateFromSelectors, Selector, - SelectorResultArray, - TypedStructuredSelectorCreator + SelectorResultArray } from 'reselect' import { createSelector, @@ -801,51 +800,6 @@ function testCreateStructuredSelector() { 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. - expectTypeOf(selectorGenerics).toEqualTypeOf(selectorGenerics1) -} - function testDynamicArrayArgument() { interface Elem { val1: string @@ -942,7 +896,7 @@ function multiArgMemoize any>( const select = createMultiMemoizeArgSelector( (state: { foo: string }) => state.foo, - foo => foo + '!' + foo => `${foo}!` ) // error is not applicable anymore select.clearCache() From ee226e6c8ee22b4aa440854559fe908267a261a1 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:13:00 -0600 Subject: [PATCH 15/60] Convert functions and lone-blocks to `test` blocks --- type-tests/deepNesting.test-d.ts | 4 +- typescript_test/test.ts | 2793 +++++++++++++++--------------- 2 files changed, 1363 insertions(+), 1434 deletions(-) diff --git a/type-tests/deepNesting.test-d.ts b/type-tests/deepNesting.test-d.ts index 5f98ff407..9a173632e 100644 --- a/type-tests/deepNesting.test-d.ts +++ b/type-tests/deepNesting.test-d.ts @@ -19,8 +19,10 @@ const state: RootState = { type AnyFunction = (...args: any[]) => any -describe('deep nesting', () => { +describe('deep nesting #525', () => { test('Deep Nesting First And Second createSelector Overload', () => { + // Verify more than 12 selectors are accepted + const selectTodos = (state: RootState) => state.todos const selector0 = createSelector(selectTodos, todos => todos) diff --git a/typescript_test/test.ts b/typescript_test/test.ts index 2a7ba5ffe..c8b8e09df 100644 --- a/typescript_test/test.ts +++ b/typescript_test/test.ts @@ -1,5 +1,3 @@ -/* 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' @@ -7,11 +5,7 @@ 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 -} from 'reselect' +import type { Selector } from 'reselect' import { createSelector, createSelectorCreator, @@ -19,15 +13,7 @@ import { lruMemoize, referenceEqualityCheck } from 'reselect' - -interface StateA { - a: number -} - -interface StateAB { - a: number - b: number -} +import type { StateA, StateAB } from '../test/testTypes' // Test exporting export const testExportBasic = createSelector( @@ -41,173 +27,164 @@ export const testExportStructured = createSelectorCreator( (a, b) => typeof a === typeof b ) -function testSelector() { - type State = { foo: string } +type Component

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

) => Component

+ +function multiArgMemoize any>( + func: F, + a: number, + b: string, + equalityCheck = referenceEqualityCheck +): F { + // @ts-ignore + return () => {} +} - const selector = createSelector( - (state: State) => state.foo, - foo => foo - ) +describe('type tests', () => { + test('selector', () => { + type State = { foo: string } - const res = selector.resultFunc('test') - selector.recomputations() - selector.resetRecomputations() + const selector = createSelector( + (state: State) => state.foo, + foo => foo + ) - const foo: string = selector({ foo: 'bar' }) + const res = selector.resultFunc('test') + selector.recomputations() + selector.resetRecomputations() - // @ts-expect-error - selector({ foo: 'bar' }, { prop: 'value' }) + const foo: string = selector({ foo: 'bar' }) - // @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 - ) -} + // @ts-expect-error + selector({ foo: 'bar' }, { prop: 'value' }) -function testNestedSelector() { - type State = { foo: string; bar: number; baz: boolean } + // @ts-expect-error + const num: number = selector({ foo: 'bar' }) - const selector = createSelector( + // allows heterogeneous parameter type input selectors 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 + (state: { foo: string }) => state.foo, + (state: { bar: number }) => state.bar, + (foo, bar) => 1 + ) - const bar1: number = bar - // @ts-expect-error - const bar2: string = bar + const selectorWithUnions = createSelector( + (state: State, val: string | number) => state.foo, + (state: State, val: string | number) => val, + (foo, val) => val + ) + }) - const baz1: boolean = baz - // @ts-expect-error - const baz2: string = baz + test('nested selector', () => { + interface State { + foo: string + bar: number + baz: boolean } - ) -} -function testSelectorAsCombiner() { - type SubState = { foo: string } - type State = { bar: SubState } + 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 + } + ) + }) - const subSelector = createSelector( - (state: SubState) => state.foo, - foo => foo - ) + test('selector as combiner', () => { + interface SubState { + foo: string + } - const selector = createSelector((state: State) => state.bar, subSelector) + interface State { + bar: SubState + } - // @ts-expect-error - selector({ foo: '' }) + const subSelector = createSelector( + (state: SubState) => state.foo, + foo => foo + ) - // @ts-expect-error - const n: number = selector({ bar: { foo: '' } }) + const selector = createSelector((state: State) => state.bar, subSelector) - const s: string = selector({ bar: { foo: '' } }) -} + // @ts-expect-error + selector({ foo: '' }) -type Component

= (props: P) => any + // @ts-expect-error + const n: number = selector({ bar: { foo: '' } }) -declare function connect( - selector: Selector -): (component: Component

) => Component

+ const s: string = selector({ bar: { foo: '' } }) + }) -function testConnect() { - connect( - createSelector( + test('connect', () => { + 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, - foo => ({ foo }) + (state: { baz: number }, props: { bar: number }) => props.bar, + (foo, bar) => ({ foo, baz: bar }) ) - )(props => { - // @ts-expect-error - props.bar - const foo: string = props.foo - }) + 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 + }) - const selector2 = createSelector( - (state: { foo: string }) => state.foo, - (state: { baz: number }, props: { bar: number }) => props.bar, - (foo, bar) => ({ foo, baz: bar }) - ) + connected({ bar: 42 }) - 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, baz: 123 }) }) - 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, + test('invalid type in combiner', () => { // @ts-expect-error - (foo: string, bar: number, baz: boolean, fizz: string) => {} - ) + createSelector( + (state: { foo: string }) => state.foo, + (foo: number) => foo + ) - // 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 } - } - ) + 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 a large array of heterogeneous parameter type - // selectors when the combinator function is typed differently - // @ts-expect-error - createSelector( - [ + // 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, @@ -216,633 +193,686 @@ function testInvalidTypeInCombinator() { (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 } - } - ) + (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 } + } + ) - const res1 = selector1({ - testString: 'a', - testNumber: 42, - testBoolean: true, - testStringArray: ['b', 'c'] + // 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 } + } + ) }) - 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 + test('parametric selector', () => { + interface State { + foo: string } - ) - - // @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 + interface Props { + bar: number } - ) - selector4({ foo: 'fizz' }, 42) -} + // 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 } + } + ) -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 res1 = selector1({ + testString: 'a', + testNumber: 42, + testBoolean: true, + testStringArray: ['b', 'c'] + }) - const ret = selector({ foo: 'fizz' }, { bar: 42 }) - const foo1: string = ret.foo1 - const foo2: string = ret.foo2 - const bar: number = ret.bar + const selector = createSelector( + (state: State) => state.foo, + (state: State, props: Props) => props.bar, + (foo, bar) => ({ foo, bar }) + ) - // @ts-expect-error - createSelector([(state: { foo: string }) => state.foo]) + // @ts-expect-error + selector({ foo: 'fizz' }) + // @ts-expect-error + selector({ foo: 'fizz' }, { bar: 'baz' }) - // @ts-expect-error - createSelector( - [ - (state: { foo: string }) => state.foo, - (state: { foo: string }) => state.foo - ], - (foo: string, bar: number) => {} - ) + const ret = selector({ foo: 'fizz' }, { bar: 42 }) + const foo: string = ret.foo + const bar: number = ret.bar - 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 - ) => {} - ) + 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 + }) + ) - // @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) => {} - ) + selector2({ foo: 'fizz' }, { bar: 42 }) - // @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 selector3 = createSelector( + (s: State) => s.foo, + (s: State, x: string) => x, + (s: State, y: number) => y, + (v, x) => { + return x + v + } + ) - { - 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 }) + selector3({ foo: 'fizz' }, 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 } - } - ) + const selector4 = createSelector( + (s: State, val: number) => s.foo, + (s: State, val: string | number) => val, + (foo, val) => { + return val + } + ) - // 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 } - } - ) + selector4({ foo: 'fizz' }, 42) + }) - // @ts-expect-error - parametric({ foo: 'fizz' }) + 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 = parametric({ foo: 'fizz' }, { bar: 42 }) + const ret = selector({ 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 - } -} + createSelector([(state: { foo: string }) => state.foo]) -function testOptionalArgumentsConflicting() { - type State = { foo: string; bar: number; baz: boolean } + // @ts-expect-error + createSelector( + [ + (state: { foo: string }) => state.foo, + (state: { foo: string }) => state.foo + ], + (foo: string, bar: number) => {} + ) - 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 - } - ) + 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 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 + 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 - selector4({} as State) - // @ts-expect-error - selector4({} as State, 'blach') - selector4({} as State, 'blach', 4) + // @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) => {} + ) - // as above but a unknown 2nd argument - const selector5 = createSelector( - (state: State, prefix: string, suffix: unknown) => - prefix + state.foo + String(suffix), - str => str - ) + 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 } + } + ) - // @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) -} + { + 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 } + } + ) -function testLruMemoize() { - const func = (a: string) => +a + // 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 } + } + ) - const memoized = lruMemoize(func) + // @ts-expect-error + parametric({ foo: 'fizz' }) - 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 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 } - ) + }) - const ret2 = memoized2('', ['1', '2']) - const str: string = ret2.str - const arr: string[] = ret2.arr -} + test('optional arguments conflicting', () => { + interface State { + foo: string + bar: number + baz: boolean + } -function testCreateSelectorCreator() { - const defaultCreateSelector = createSelectorCreator(lruMemoize) + 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 + } + ) - const selector = defaultCreateSelector( - (state: { foo: string }) => state.foo, - foo => foo - ) - const value: string = selector({ foo: 'fizz' }) + // @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) - // @ts-expect-error - selector({ foo: 'fizz' }, { bar: 42 }) + const selector2 = createSelector( + (state: State, prefix: any) => prefix + state.foo, + str => str + ) - // clearCache should exist because of lruMemoize - selector.clearCache() + // @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) - const parametric = defaultCreateSelector( - (state: { foo: string }) => state.foo, - (state: { foo: string }, props: { bar: number }) => props.bar, - (foo, bar) => ({ foo, bar }) - ) + // 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 + ) - // @ts-expect-error - parametric({ foo: 'fizz' }) + selector3({} as State) + selector3({} as State, 1) + selector3({} as State, 'blach') - const ret = parametric({ foo: 'fizz' }, { bar: 42 }) - const foo: string = ret.foo - const bar: number = ret.bar + // 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 - createSelectorCreator(lruMemoize, 1) + // @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 + ) - createSelectorCreator(lruMemoize, (a: T, b: T) => { - return `${a}` === `${b}` - }) -} + // @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 + ) -function testCreateStructuredSelector() { - const oneParamSelector = createStructuredSelector({ - foo: (state: StateAB) => state.a, - bar: (state: StateAB) => state.b - }) + 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 + ) - const threeParamSelector = createStructuredSelector({ - foo: (state: StateAB, c: number, d: string) => state.a, - bar: (state: StateAB, c: number, d: string) => state.b + // @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) }) - interface RootState { - foo: string - bar: number - } + test('LruMemoize', () => { + const func = (a: string) => +a + + const memoized = lruMemoize(func) - const typedStructuredSelectorCreator = - createStructuredSelector.withTypes() + 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 selector = typedStructuredSelectorCreator({ - foo: state => state.foo, - bar: state => +state.foo + const ret2 = memoized2('', ['1', '2']) + const str: string = ret2.str + const arr: string[] = ret2.arr }) - const res1 = selector({ foo: '42', bar: 1 }) - const foo: string = res1.foo - const bar: number = res1.bar + test('createSelectorCreator', () => { + const defaultCreateSelector = createSelectorCreator(lruMemoize) - // @ts-expect-error - selector({ bar: '42' }) + const selector = defaultCreateSelector( + (state: { foo: string }) => state.foo, + foo => foo + ) + const value: string = selector({ foo: 'fizz' }) - // @ts-expect-error - selector({ foo: '42' }, { bar: 42 }) + // @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 }) + ) - typedStructuredSelectorCreator({ // @ts-expect-error - bar: (state: { baz: boolean }) => 1 - }) + parametric({ foo: 'fizz' }) - typedStructuredSelectorCreator({ - bar: state => state.foo - }) + const ret = parametric({ foo: 'fizz' }, { bar: 42 }) + const foo: string = ret.foo + const bar: number = ret.bar + + // @ts-expect-error + createSelectorCreator(lruMemoize, 1) - typedStructuredSelectorCreator({ - baz: state => state.foo + createSelectorCreator(lruMemoize, (a: T, b: T) => { + return `${a}` === `${b}` + }) }) - // 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 + test('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 + }) - const selector2 = createStructuredSelector({ - foo: FooSelector, - bar: BarSelector - }) + 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 - const selectorGenerics = createStructuredSelector<{ - foo: typeof FooSelector - bar: typeof BarSelector - }>({ - foo: state => state.foo, - bar: state => +state.foo + // @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 + 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 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' }) }) - type ExpectedResult = { - foo: string - bar: number - } + test('dynamic array argument', () => { + interface Elem { + val1: string + val2: string + } + const data: ReadonlyArray = [ + { val1: 'a', val2: 'aa' }, + { val1: 'b', val2: 'bb' } + ] - 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' }) -} + createSelector( + data.map(obj => () => obj.val1), + (...vals) => vals.join(',') + ) -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), + createSelector( + data.map(obj => () => obj.val1), + // @ts-expect-error + vals => vals.join(',') + ) + + createSelector( + data.map(obj => () => obj.val1), + (...vals: string[]) => 0 + ) // @ts-expect-error - vals => vals.join(',') - ) + createSelector( + data.map(obj => () => obj.val1), + (...vals: number[]) => 0 + ) - 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') -} + 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 = { +test('structured selector type parameters', () => { + interface GlobalState { foo: string bar: number } @@ -857,826 +887,723 @@ function testStructuredSelectorTypeParams() { // 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 - ) -} + test('#384: check for lruMemoize', () => { + interface Transaction { + transactionId: string + } -// #445 -function issue445() { - interface TestState { - someNumber: number | null - someString: string | null - } + const toId = (transaction: Transaction) => transaction.transactionId + const transactionsIds = (transactions: Transaction[]) => + transactions.map(toId) + const collectionsEqual = (ts1: Transaction[], ts2: Transaction[]) => + isEqual(transactionsIds(ts1), transactionsIds(ts2)) - interface Object1 { - str: string - } - interface Object2 { - num: number - } + const createTransactionsSelector = createSelectorCreator( + lruMemoize, + collectionsEqual + ) - const getNumber = (state: TestState) => state.someNumber - const getString = (state: TestState) => state.someString + const createMultiMemoizeArgSelector = createSelectorCreator( + multiArgMemoize, + 42, + 'abcd', + referenceEqualityCheck + ) - 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 - } + const select = createMultiMemoizeArgSelector( + (state: { foo: string }) => state.foo, + foo => `${foo}!` + ) + // error is not applicable anymore + select.clearCache() - // ################ Tests ################ + const createMultiMemoizeArgSelector2 = createSelectorCreator( + multiArgMemoize, + 42, + // @ts-expect-error + referenceEqualityCheck + ) - // Compact selector examples + const groupTransactionsByLabel = lruMemoize( + (transactions: Transaction[]) => + groupBy(transactions, item => item.transactionId), + collectionsEqual + ) + }) - // Should error because generateObject1 can't take null - // @ts-expect-error - const getObject1 = createSelector([getString], generateObject1) + test('issue445', () => { + // #445 - // Should error because generateObject2 can't take null - // @ts-expect-error - const getObject2 = createSelector([getNumber], generateObject2) + interface TestState { + someNumber: number | null + someString: string | null + } - // Should error because mismatch of params - // @ts-expect-error - const getComplexObjectTest1 = createSelector( - [getObject1], - generateComplexObject - ) + interface Object1 { + str: string + } + interface Object2 { + num: number + } - // 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 - ) + const getNumber = (state: TestState) => state.someNumber + const getString = (state: TestState) => state.someString - // Should error because number can't be null - // @ts-expect-error - const getComplexObjectTest3 = createSelector( - [getNumber, getObject1, getObject2], - generateComplexObject - ) + 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 + } - // 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 - ) + // ################ Tests ################ - // Verbose selector examples + // Compact selector examples - // Errors correctly, says str can't be null - const getVerboseObject1 = createSelector([getString], str => + // Should error because generateObject1 can't take null // @ts-expect-error - generateObject1(str) - ) + const getObject1 = createSelector([getString], generateObject1) - // Errors correctly, says num can't be null - const getVerboseObject2 = createSelector([getNumber], num => + // Should error because generateObject2 can't take null // @ts-expect-error - generateObject2(num) - ) + const getObject2 = createSelector([getNumber], generateObject2) - // Errors correctly - const getVerboseComplexObjectTest1 = createSelector([getObject1], obj1 => + // Should error because mismatch of params // @ts-expect-error - generateComplexObject(obj1) - ) + const getComplexObjectTest1 = createSelector( + [getObject1], + generateComplexObject + ) - // Errors correctly - const getVerboseComplexObjectTest2 = createSelector( - [getNumber, getObject1], + // Does error, but error is really weird and talks about "Object1 is not assignable to type number" // @ts-expect-error - (num, obj1) => generateComplexObject(num, obj1) - ) + const getComplexObjectTest2 = createSelector( + [getNumber, getObject1], + generateComplexObject + ) - // Errors correctly - const getVerboseComplexObjectTest3 = createSelector( - [getNumber, getObject1, getObject2], + // Should error because number can't be null // @ts-expect-error - (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) - ) + const getComplexObjectTest3 = createSelector( + [getNumber, getObject1, getObject2], + generateComplexObject + ) - // Errors correctly - const getVerboseComplexObjectTest4 = createSelector( - [getObject1, getNumber, getObject2], + // Does error, but error is really weird and talks about "Object1 is not assignable to type number" // @ts-expect-error - (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) - ) -} + const getComplexObjectTest4 = createSelector( + [getObject1, getNumber, getObject2], + generateComplexObject + ) -// #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 - ) -} + // Verbose selector examples -function customMemoizationOptionTypes() { - const customMemoize = ( - f: (...args: any[]) => any, - a: string, - b: number, - c: boolean - ) => { - return f - } + // Errors correctly, says str can't be null + const getVerboseObject1 = createSelector([getString], str => + // @ts-expect-error + generateObject1(str) + ) - const customSelectorCreatorCustomMemoizeWorking = createSelectorCreator( - customMemoize, - 'a', - 42, - true - ) + // Errors correctly, says num can't be null + const getVerboseObject2 = createSelector([getNumber], num => + // @ts-expect-error + generateObject2(num) + ) - // @ts-expect-error - const customSelectorCreatorCustomMemoizeMissingArg = createSelectorCreator( - customMemoize, - 'a', - true - ) -} + // Errors correctly + const getVerboseComplexObjectTest1 = createSelector([getObject1], obj1 => + // @ts-expect-error + generateComplexObject(obj1) + ) -// 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 - } - ) + // Errors correctly + const getVerboseComplexObjectTest2 = createSelector( + [getNumber, getObject1], + // @ts-expect-error + (num, obj1) => generateComplexObject(num, obj1) + ) - const lruMemoizeAcceptsFirstArgAsObject = createSelector( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoize: lruMemoize, - memoizeOptions: { - equalityCheck: (a, b) => a === b - } - } - ) + // Errors correctly + const getVerboseComplexObjectTest3 = createSelector( + [getNumber, getObject1, getObject2], + // @ts-expect-error + (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) + ) - const lruMemoizeAcceptsArgsAsArray = createSelector( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoize: lruMemoize, - memoizeOptions: [(a, b) => a === b] - } - ) + // Errors correctly + const getVerboseComplexObjectTest4 = createSelector( + [getObject1, getNumber, getObject2], + // @ts-expect-error + (num, obj1, obj2) => generateComplexObject(num, obj1, obj2) + ) + }) - const customSelectorCreatorMicroMemoize = createSelectorCreator( - microMemoize, - { - maxSize: 42 + test('issue492', () => { + // #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('custom memoization option types', () => { + const customMemoize = ( + f: (...args: any[]) => any, + a: string, + b: number, + c: boolean + ) => { + return f } - ) - customSelectorCreatorMicroMemoize( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoizeOptions: [ - { - maxSize: 42 + const customSelectorCreatorCustomMemoizeWorking = createSelectorCreator( + customMemoize, + 'a', + 42, + true + ) + + // @ts-expect-error + const customSelectorCreatorCustomMemoizeMissingArg = createSelectorCreator( + customMemoize, + 'a', + true + ) + }) + + test('createSelector 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 customSelectorCreatorMemoizeOne = createSelectorCreator(memoizeOne) + const lruMemoizeAcceptsArgsAsArray = createSelector( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoize: lruMemoize, + memoizeOptions: [(a, b) => a === b] + } + ) - customSelectorCreatorMemoizeOne( - (state: StateAB) => state.a, - (state: StateAB) => state.b, - (a, b) => a + b, - { - memoizeOptions: (a, b) => a === b - } - ) -} + const customSelectorCreatorMicroMemoize = createSelectorCreator( + microMemoize, + { + maxSize: 42 + } + ) -// 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 -) + customSelectorCreatorMicroMemoize( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoizeOptions: [ + { + maxSize: 42 + } + ] + } + ) -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 customSelectorCreatorMemoizeOne = createSelectorCreator(memoizeOne) -{ - 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: '' }) -} + customSelectorCreatorMemoizeOne( + (state: StateAB) => state.a, + (state: StateAB) => state.b, + (a, b) => a + b, + { + memoizeOptions: (a, b) => a === b + } + ) + }) -// 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 } - } - ) + test('ensure that input selectors with mismatched states raise errors', () => { + const input1 = (state: string) => 1 + const input2 = (state: number) => 2 - // Make sure inference of functions works... - const selector3: SelectorType = createSelector(input, result) - const selector4: SelectorType = createSelector(input, result, { - memoize: lruMemoize, - memoizeOptions: { maxSize: 42 } + 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: '' }) }) -} -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) -} + test('input selector with undefined return', () => { + // Issue #526 -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 }) -} + interface Input { + field: number | undefined + } -function issue548() { - interface State { - value: Record | null - loading: boolean - } + type Output = string - interface Props { - currency: string - } + type SelectorType = (input: Input) => Output + + const input = ({ field }: Input) => field - const isLoading = createSelector( - (state: State) => state, - (_: State, props: Props) => props.currency, - ({ loading }, currency) => loading - ) + const result = (out: number | undefined): Output => 'test' - const mapData = createStructuredSelector({ - isLoading, - test2: (state: State) => 42 + // 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 } + }) }) - const result = mapData({ value: null, loading: false }, { currency: 'EUR' }) -} + test('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 + ) -function issue550() { - const some = createSelector( - (a: number) => a, - (_a: number, b: number) => b, - (a, b) => a + b - ) + const state: StateA = { a: 42 } + const test = testSelector( + state, + { + testNumber: 1, + testString: '10', + testBoolean: true, + testString2: 'blah' + }, + 42, + 'blah' + ) - const test = some(1, 2) -} + // #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] + ) -function rtkIssue1750() { - const slice = createSlice({ - name: 'test', - initialState: 0, - reducers: {} + selectProp1({ a: 42 }, { prop1: 1 }) + // @ts-expect-error + selectProp2({ a: 42 }, { prop2: 2 }) }) - interface Pokemon { - name: string - } + test('issue548', () => { + interface State { + value: Record | null + loading: boolean + } - // 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}` - }) + 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' }) }) - const store = configureStore({ - reducer: { - test: slice.reducer, - [pokemonApi.reducerPath]: pokemonApi.reducer - }, - middleware: getDefaultMiddleware => - getDefaultMiddleware().concat(pokemonApi.middleware) + test('issue550', () => { + const some = createSelector( + (a: number) => a, + (_a: number, b: number) => b, + (a, b) => a + b + ) + + const test = some(1, 2) }) - type RootState = ReturnType + test('rtkIssue1750', () => { + const slice = createSlice({ + name: 'test', + initialState: 0, + reducers: {} + }) + + interface Pokemon { + name: string + } - const selectTest = createSelector( - (state: RootState) => state.test, - test => test - ) + // 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 useAppSelector: TypedUseSelectorHook = useSelector + const store = configureStore({ + reducer: { + test: slice.reducer, + [pokemonApi.reducerPath]: pokemonApi.reducer + }, + middleware: getDefaultMiddleware => + getDefaultMiddleware().concat(pokemonApi.middleware) + }) - // Selector usage should compile correctly - const testItem = selectTest(store.getState()) + type RootState = ReturnType - function App() { - const test = useAppSelector(selectTest) - return null - } -} + const selectTest = createSelector( + (state: RootState) => state.test, + test => test + ) -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 useAppSelector: TypedUseSelectorHook = useSelector - const input1b = (_: StateA, param: { b: string }) => param.b + // Selector usage should compile correctly + const testItem = selectTest(store.getState()) - const testSelector1 = createSelector(input1a, input1b, () => ({})) + function App() { + const test = useAppSelector(selectTest) + return null + } + }) - // @ts-expect-error - testSelector1({ a: 42 }, { b: 99 }) // should not compile + 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 input2a = (_: StateA, param: { b: { c: number } }) => param.b.c - const input2b = (_: StateA, param: { b: { c: string } }) => param.b.c + const input1b = (_: StateA, param: { b: string }) => param.b - const testSelector2 = createSelector(input2a, input2b, (c1, c2) => {}) + const testSelector1 = createSelector(input1a, input1b, () => ({})) - // @ts-expect-error - testSelector2({ a: 42 }, { b: { c: 99 } }) -} + // @ts-expect-error + testSelector1({ a: 42 }, { b: 99 }) // should not compile -function issue554a() { - interface State { - foo: string - bar: number - } + const input2a = (_: StateA, param: { b: { c: number } }) => param.b.c + const input2b = (_: StateA, param: { b: { c: string } }) => param.b.c - const initialState: State = { - foo: 'This is Foo', - bar: 1 - } + const testSelector2 = createSelector(input2a, input2b, (c1, c2) => {}) - const getFoo = (state: State) => { - return state.foo - } - getFoo(initialState) + // @ts-expect-error + testSelector2({ a: 42 }, { b: { c: 99 } }) + }) - const getBar = (state: State) => { - return state.bar - } - getBar(initialState) + test('issue554a', () => { + interface State { + foo: string + bar: number + } + + const initialState: State = { + foo: 'This is Foo', + bar: 1 + } - const simple = createSelector(getFoo, getBar, (foo, bar) => { - return `${foo} => ${bar}` + 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') }) - 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}` + + test('issue554b', () => { + interface State { + counter1: number + counter2: number } - ) - complexOne(initialState, 'first') - - const complexTwo = createSelector( - getFoo, - getBar, - firstInput, - secondInput, - (foo, bar, first, second) => { - return `${foo} => ${bar} || ${first} and ${second}` + + 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('issue554c', () => { + interface State { + counter1: number + counter2: number } - ) - // 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, // `numberA` is optional + (state: State) => state.counter2, + (numberA, counter2) => (numberA ? numberA + counter2 : counter2) + ) - const selectTest = createSelector( - (state: State, numberA?: number) => numberA, - (state: State) => state.counter2, - (numberA, counter2) => (numberA ? numberA + counter2 : counter2) - ) + // @ts-expect-error + const value = selectTest({ counter1: 0, counter2: 0 }, 'what?') - type selectTestParams = Parameters - const p1: selectTestParams = [{ counter1: 1, counter2: 2 }, 42] + const selectTest2 = createSelector( + (state: State, numberA: number) => numberA, // `numberA` is not optional anymore + (state: State) => state.counter2, + (numberA, counter2) => (numberA ? numberA + counter2 : counter2) + ) - expectTypeOf(p1).toEqualTypeOf<[State, number?]>() + // @ts-expect-error + const value2 = selectTest2({ counter1: 0, counter2: 0 }, 'what?') + }) - const result = selectTest({ counter1: 1, counter2: 2 }, 42) -} + test('issue555', () => { + interface IReduxState { + ui: { + x: string + y: string + } + } -function issue554c() { - interface State { - counter1: number - counter2: number - } + const someSelector1 = createSelector( + (state: IReduxState, param: 'x' | 'y' | undefined) => + param !== undefined ? state.ui[param] : null, + (a: string | null) => a + ) - const selectTest = createSelector( - (state: State, numberA?: number) => numberA, // `numberA` is optional - (state: State) => state.counter2, - (numberA, counter2) => (numberA ? numberA + counter2 : counter2) - ) + const someSelector2 = createSelector( + (state: IReduxState, param?: 'x' | 'y') => + param !== undefined ? state.ui[param] : null, + (a: string | null) => a + ) - // @ts-expect-error - const value = selectTest({ counter1: 0, counter2: 0 }, 'what?') + const someSelector3 = createSelector( + (state: IReduxState, param: 'x' | 'y' | null) => + param !== null ? state.ui[param] : null, + (a: string | null) => a + ) - const selectTest2 = createSelector( - (state: State, numberA: number) => numberA, // `numberA` is not optional anymore - (state: State) => state.counter2, - (numberA, counter2) => (numberA ? numberA + counter2 : counter2) - ) + const state = { ui: { x: '1', y: '2' } } - // @ts-expect-error - const value2 = selectTest2({ counter1: 0, counter2: 0 }, 'what?') -} + const selectorResult1 = someSelector1(state, undefined) + const selectorResult2 = someSelector2(state, undefined) + const selectorResult3 = someSelector3(state, null) + }) -function issue555() { - type IReduxState = { - ui: { - x: string - y: string + test('createStructuredSelector new', () => { + interface State { + todos: { + id: number + completed: boolean + }[] } - } - 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) -} + const state: State = { + todos: [ + { id: 0, completed: false }, + { id: 1, completed: false } + ] + } -function testCreateStructuredSelectorNew() { - interface State { - todos: { - id: number - completed: boolean - }[] - } - const state: State = { - todos: [ + 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: 1, completed: false } - ] - } + [{ id: 0, completed: false }] + ).selectedCompletedTodos - 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 - - expectTypeOf(multiArgsStructuredSelector.argsMemoize).toEqualTypeOf( - microMemoize - ) - - expectTypeOf(multiArgsStructuredSelector.memoize).toEqualTypeOf(microMemoize) - - expectTypeOf(multiArgsStructuredSelector.dependencies).toEqualTypeOf< - [ - (state: State) => State['todos'], - (state: State, id: number) => State['todos'][number], - (state: State, id: number, isCompleted: boolean) => State['todos'] - ] - >() + multiArgsStructuredSelector.memoizedResultFunc( + [{ id: 2, completed: true }], + { id: 0, completed: false }, + [{ id: 0, completed: false }] + ).selectedCompletedTodos - // @ts-expect-error Wrong number of arguments. - multiArgsStructuredSelector(state, 2) -} + multiArgsStructuredSelector.memoizedResultFunc.cache + multiArgsStructuredSelector.memoizedResultFunc.fn + multiArgsStructuredSelector.memoizedResultFunc.isMemoized + multiArgsStructuredSelector.memoizedResultFunc.options + + multiArgsStructuredSelector(state, 2, true).selectedCompletedTodos + + expectTypeOf(multiArgsStructuredSelector.argsMemoize).toEqualTypeOf( + microMemoize + ) + + expectTypeOf(multiArgsStructuredSelector.memoize).toEqualTypeOf( + microMemoize + ) + + expectTypeOf(multiArgsStructuredSelector.dependencies).toEqualTypeOf< + [ + (state: State) => State['todos'], + (state: State, id: number) => State['todos'][number], + (state: State, id: number, isCompleted: boolean) => State['todos'] + ] + >() + + // @ts-expect-error Wrong number of arguments. + multiArgsStructuredSelector(state, 2) + }) +}) From 0ec452ffbcb12649eb15f34c3ccec91c1768523c Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:14:19 -0600 Subject: [PATCH 16/60] Move `test.ts` into `type-tests` folder --- {typescript_test => type-tests}/test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {typescript_test => type-tests}/test.ts (100%) diff --git a/typescript_test/test.ts b/type-tests/test.ts similarity index 100% rename from typescript_test/test.ts rename to type-tests/test.ts From 1fe9770f12bcd8b9d3785d95df6b902f0abacff1 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:15:02 -0600 Subject: [PATCH 17/60] Remove `typesTestUtils.ts` as it is no longer needed --- typescript_test/typesTestUtils.ts | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 typescript_test/typesTestUtils.ts diff --git a/typescript_test/typesTestUtils.ts b/typescript_test/typesTestUtils.ts deleted file mode 100644 index 8703bb027..000000000 --- a/typescript_test/typesTestUtils.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type IsEqual = (() => G extends A ? 1 : 2) extends < - G ->() => G extends B ? 1 : 2 - ? true - : false From 378acb00aac1ec9ae47b4e8e7cfa28f2e4b84f6b Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:17:05 -0600 Subject: [PATCH 18/60] Update `test` command in `package.json` to use `yarn bin vitest` --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 83e3b9cb1..3f4f1e248 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "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", From 6f7011fce66d97b61868157ccc07aa8b1f9be6ba Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:17:18 -0600 Subject: [PATCH 19/60] Fix `test:typescript` command --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f4f1e248..e881dc1ce 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "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", + "test:typescript": "tsc --noEmit -p tsconfig.test.json", "docs:start": "yarn --cwd website start", "docs:build": "yarn --cwd website build", "docs:clear": "yarn --cwd website clear", From afd022d1749e7be2292fbb7f6ab1c61d498790c3 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:24:53 -0600 Subject: [PATCH 20/60] Rename `test:typescript` command to `type-tests` - Rename `test:typescript` command to `type-tests` in `package.json` to be more consistent with RTK. --- .github/workflows/build-and-test-types.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test-types.yml b/.github/workflows/build-and-test-types.yml index cd4283f3e..39c847487 100644 --- a/.github/workflows/build-and-test-types.yml +++ b/.github/workflows/build-and-test-types.yml @@ -89,7 +89,7 @@ jobs: - name: Test types run: | ./node_modules/.bin/tsc --version - yarn test:typescript + yarn type-tests are-the-types-wrong: name: Check package config with are-the-types-wrong diff --git a/package.json b/package.json index e881dc1ce..ca94768aa 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "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 tsconfig.test.json", + "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", From 313be9e0bc4ad94bd6bc6b0f9e26f51d01bb7ce0 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:39:23 -0600 Subject: [PATCH 21/60] Fix imports inside test files --- test/identityFunctionCheck.test.ts | 2 +- test/testUtils.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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/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 From 65bd93645dc7e88450769a40ad860417da409965 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 12:38:58 -0600 Subject: [PATCH 22/60] Fix type issues in `createSelector.withTypes.test-d.ts` --- type-tests/createSelector.withTypes.test-d.ts | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/type-tests/createSelector.withTypes.test-d.ts b/type-tests/createSelector.withTypes.test-d.ts index aa517b6dd..26c4d8e88 100644 --- a/type-tests/createSelector.withTypes.test-d.ts +++ b/type-tests/createSelector.withTypes.test-d.ts @@ -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() + 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) ) }) }) From 047a56436c9a737c60adaff6007cef1bcd8e3d73 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 12:39:58 -0600 Subject: [PATCH 23/60] Add `tsconfig.vitest-temp.json` to `.gitignore` file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 7a4a7e462..9bd845cd0 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ website/.yarn/ docs/examples/**/*.js docs/examples/**/*.jsx + +tsconfig.vitest-temp.json \ No newline at end of file From ad9ad27cd79d4fe4b224445725a7af99cbef3512 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 03:21:20 -0600 Subject: [PATCH 24/60] Move "nested selector" type test to `deepNesting.test-d.ts` --- type-tests/deepNesting.test-d.ts | 31 +++++++++++++++++++++++++++++++ type-tests/test.ts | 30 ------------------------------ 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/type-tests/deepNesting.test-d.ts b/type-tests/deepNesting.test-d.ts index 9a173632e..5ba856d90 100644 --- a/type-tests/deepNesting.test-d.ts +++ b/type-tests/deepNesting.test-d.ts @@ -402,4 +402,35 @@ describe('deep nesting #525', () => { } ) }) + + 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/test.ts b/type-tests/test.ts index c8b8e09df..ff137f68f 100644 --- a/type-tests/test.ts +++ b/type-tests/test.ts @@ -78,36 +78,6 @@ describe('type tests', () => { ) }) - 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 - } - ) - }) - test('selector as combiner', () => { interface SubState { foo: string From 17f8b8f7f3b274d95865da0144e017bf9807dd5a Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 03:24:53 -0600 Subject: [PATCH 25/60] Move `lruMemoize` type tests into its own file --- type-tests/lruMemoize.test-d.ts | 27 +++++++++++++++++++++++++++ type-tests/test.ts | 24 ------------------------ 2 files changed, 27 insertions(+), 24 deletions(-) create mode 100644 type-tests/lruMemoize.test-d.ts diff --git a/type-tests/lruMemoize.test-d.ts b/type-tests/lruMemoize.test-d.ts new file mode 100644 index 000000000..a84a35abe --- /dev/null +++ b/type-tests/lruMemoize.test-d.ts @@ -0,0 +1,27 @@ +import { lruMemoize } from 'reselect' + +describe('type tests', () => { + test('lruMemoize', () => { + 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 + }) +}) diff --git a/type-tests/test.ts b/type-tests/test.ts index ff137f68f..897759d5a 100644 --- a/type-tests/test.ts +++ b/type-tests/test.ts @@ -650,30 +650,6 @@ describe('type tests', () => { selector8({} as State, 2) }) - test('LruMemoize', () => { - 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 - }) - test('createSelectorCreator', () => { const defaultCreateSelector = createSelectorCreator(lruMemoize) From afe10bca66e0d5d421f8ff846db948c2eac017af Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 03:27:25 -0600 Subject: [PATCH 26/60] Move `createSelectorCreator` type tests into its own file --- type-tests/createSelectorCreator.test-d.ts | 39 +++++++++++++++++++++- type-tests/test.ts | 36 -------------------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/type-tests/createSelectorCreator.test-d.ts b/type-tests/createSelectorCreator.test-d.ts index 76f358b0a..1cbf6f38c 100644 --- a/type-tests/createSelectorCreator.test-d.ts +++ b/type-tests/createSelectorCreator.test-d.ts @@ -25,7 +25,7 @@ const state: RootState = { ] } -describe('createSelectorCreator', () => { +describe('type tests', () => { test('options object as argument', () => { const createSelectorDefault = createSelectorCreator({ memoize: lruMemoize @@ -55,4 +55,41 @@ 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 + ) + 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}` + }) + }) + }) diff --git a/type-tests/test.ts b/type-tests/test.ts index 897759d5a..12e5d9a66 100644 --- a/type-tests/test.ts +++ b/type-tests/test.ts @@ -650,42 +650,6 @@ describe('type tests', () => { selector8({} as State, 2) }) - test('createSelectorCreator', () => { - 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}` - }) - }) - test('createStructuredSelector', () => { const oneParamSelector = createStructuredSelector({ foo: (state: StateAB) => state.a, From c28daec7dcc788ccacf82a6efeaec03f9013bb6c Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 03:32:33 -0600 Subject: [PATCH 27/60] Remove duplicate`createStructuredSelector.withTypes()` type tests --- type-tests/test.ts | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/type-tests/test.ts b/type-tests/test.ts index 12e5d9a66..8bf22b20d 100644 --- a/type-tests/test.ts +++ b/type-tests/test.ts @@ -661,42 +661,6 @@ describe('type tests', () => { 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 interface State { foo: string @@ -725,7 +689,6 @@ describe('type tests', () => { 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' }, From 8c06726c524dbcd319fe06869c2620e2504964a9 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 04:04:43 -0600 Subject: [PATCH 28/60] Move `createStructuredSelector` type tests into its own file --- type-tests/createStructuredSelector.test-d.ts | 162 ++++++++++++++++- type-tests/test.ts | 170 ------------------ 2 files changed, 161 insertions(+), 171 deletions(-) diff --git a/type-tests/createStructuredSelector.test-d.ts b/type-tests/createStructuredSelector.test-d.ts index 97a3be8df..0ce58e516 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 @@ -35,7 +37,6 @@ const rootState: RootState = { } describe('createStructuredSelector', () => { - // TODO: Remove this test block once `TypedStructuredSelectorCreator` is removed. test('TypedStructuredSelectorCreator should lock down state type', () => { const createStructuredAppSelector: TypedStructuredSelectorCreator = @@ -244,4 +245,163 @@ describe('createStructuredSelector', () => { 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', () => { + 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/test.ts b/type-tests/test.ts index 8bf22b20d..501a8aec7 100644 --- a/type-tests/test.ts +++ b/type-tests/test.ts @@ -9,7 +9,6 @@ import type { Selector } from 'reselect' import { createSelector, createSelectorCreator, - createStructuredSelector, lruMemoize, referenceEqualityCheck } from 'reselect' @@ -650,58 +649,6 @@ describe('type tests', () => { selector8({} as State, 2) }) - test('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 - }) - - // Test automatic inference of types for createStructuredSelector via overload - 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('dynamic array argument', () => { interface Elem { val1: string @@ -742,24 +689,6 @@ describe('type tests', () => { // @ts-expect-error s({ a: 42 }, 'val3') }) -}) - -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('#384: check for lruMemoize', () => { interface Transaction { @@ -1165,30 +1094,6 @@ test('structured selector type parameters', () => { selectProp2({ a: 42 }, { prop2: 2 }) }) - test('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' }) - }) - test('issue550', () => { const some = createSelector( (a: number) => a, @@ -1404,79 +1309,4 @@ test('structured selector type parameters', () => { const selectorResult2 = someSelector2(state, undefined) const selectorResult3 = someSelector3(state, null) }) - - test('createStructuredSelector new', () => { - 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 - - expectTypeOf(multiArgsStructuredSelector.argsMemoize).toEqualTypeOf( - microMemoize - ) - - expectTypeOf(multiArgsStructuredSelector.memoize).toEqualTypeOf( - microMemoize - ) - - expectTypeOf(multiArgsStructuredSelector.dependencies).toEqualTypeOf< - [ - (state: State) => State['todos'], - (state: State, id: number) => State['todos'][number], - (state: State, id: number, isCompleted: boolean) => State['todos'] - ] - >() - - // @ts-expect-error Wrong number of arguments. - multiArgsStructuredSelector(state, 2) - }) }) From eb46ed130f71085f67db49ef56d87fd1ae512f7e Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 04:35:40 -0600 Subject: [PATCH 29/60] Move `createSelector` type tests into its own file --- type-tests/createSelector.test-d.ts | 1237 +++++++++++++++++++++++++++ 1 file changed, 1237 insertions(+) create mode 100644 type-tests/createSelector.test-d.ts diff --git a/type-tests/createSelector.test-d.ts b/type-tests/createSelector.test-d.ts new file mode 100644 index 000000000..431499c2e --- /dev/null +++ b/type-tests/createSelector.test-d.ts @@ -0,0 +1,1237 @@ +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 + ) + + 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 + ) + }) + + 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) + + // @ts-expect-error + selector({ foo: '' }) + + // @ts-expect-error + const n: number = selector({ bar: { foo: '' } }) + + const s: string = selector({ bar: { foo: '' } }) + }) + + test('connect', () => { + 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 }) + }) + + 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 } + } + ) + + 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) + }) + + 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 }) + 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 + } + }) + + 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 => { + 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) + }) + + 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 + } + ) + }) +}) From 09ebd58df221a53207d46a3a6ed5ff4131d16a48 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 04:36:56 -0600 Subject: [PATCH 30/60] Move some more `lruMemoize` type tests into its own file --- type-tests/lruMemoize.test-d.ts | 63 ++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/type-tests/lruMemoize.test-d.ts b/type-tests/lruMemoize.test-d.ts index a84a35abe..3b3e69ed0 100644 --- a/type-tests/lruMemoize.test-d.ts +++ b/type-tests/lruMemoize.test-d.ts @@ -1,4 +1,9 @@ -import { lruMemoize } from 'reselect' +import { groupBy, isEqual } from 'lodash' +import { + createSelectorCreator, + lruMemoize, + referenceEqualityCheck +} from 'reselect' describe('type tests', () => { test('lruMemoize', () => { @@ -24,4 +29,60 @@ describe('type tests', () => { const str: string = ret2.str const arr: string[] = ret2.arr }) + + test('issue #384', () => { + // https://github.com/reduxjs/reselect/issues/384 + + function multiArgMemoize any>( + func: F, + a: number, + b: string, + equalityCheck = referenceEqualityCheck + ): F { + // @ts-ignore + return () => {} + } + + 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 + ) + }) }) From be27163dd2e17903a13b2d282783868e2faf146b Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 04:37:17 -0600 Subject: [PATCH 31/60] Move some more `createSelectorCreator` type tests into its own file --- type-tests/createSelectorCreator.test-d.ts | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/type-tests/createSelectorCreator.test-d.ts b/type-tests/createSelectorCreator.test-d.ts index 1cbf6f38c..f34632826 100644 --- a/type-tests/createSelectorCreator.test-d.ts +++ b/type-tests/createSelectorCreator.test-d.ts @@ -9,6 +9,12 @@ import { } 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 }[] @@ -92,4 +98,28 @@ describe('type tests', () => { }) }) + test('custom memoization option types', () => { + 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 + ) + }) }) From e994832b8d9a25e60e26b8731cfc4b2555e32f6b Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 04:38:49 -0600 Subject: [PATCH 32/60] Move type tests inside `test.ts` into their respective files --- type-tests/createStructuredSelector.test-d.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/type-tests/createStructuredSelector.test-d.ts b/type-tests/createStructuredSelector.test-d.ts index 0ce58e516..e6a665340 100644 --- a/type-tests/createStructuredSelector.test-d.ts +++ b/type-tests/createStructuredSelector.test-d.ts @@ -36,7 +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 = @@ -315,7 +315,9 @@ describe('createStructuredSelector', () => { }) }) - test('issue #548', () => { + test("issue #548: createStructuredSelector doesn't infer props typings", () => { + // https://github.com/reduxjs/reselect/issues/548 + interface State { value: Record | null loading: boolean From 05bc1d1bd97e6d1cbdbe5c2358843c78be5ccc62 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 04:39:14 -0600 Subject: [PATCH 33/60] Remove `test.ts` --- type-tests/test.ts | 1312 -------------------------------------------- 1 file changed, 1312 deletions(-) delete mode 100644 type-tests/test.ts diff --git a/type-tests/test.ts b/type-tests/test.ts deleted file mode 100644 index 501a8aec7..000000000 --- a/type-tests/test.ts +++ /dev/null @@ -1,1312 +0,0 @@ -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 { Selector } from 'reselect' -import { - createSelector, - createSelectorCreator, - lruMemoize, - referenceEqualityCheck -} from 'reselect' -import type { StateA, StateAB } from '../test/testTypes' - -// 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 -) - -type Component

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

) => Component

- -function multiArgMemoize any>( - func: F, - a: number, - b: string, - equalityCheck = referenceEqualityCheck -): F { - // @ts-ignore - return () => {} -} - -describe('type tests', () => { - test('selector', () => { - 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 - ) - }) - - 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) - - // @ts-expect-error - selector({ foo: '' }) - - // @ts-expect-error - const n: number = selector({ bar: { foo: '' } }) - - const s: string = selector({ bar: { foo: '' } }) - }) - - test('connect', () => { - 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 }) - }) - - 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 } - } - ) - - 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) - }) - - 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 }) - 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 - } - }) - - 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 => { - 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) - }) - - 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('#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 - ) - }) - - test('issue445', () => { - // #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('issue492', () => { - // #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('custom memoization option types', () => { - 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 - ) - }) - - test('createSelector 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 - } - ) - }) - - 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('input selector with undefined return', () => { - // Issue #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('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 }) - }) - - test('issue550', () => { - const some = createSelector( - (a: number) => a, - (_a: number, b: number) => b, - (a, b) => a + b - ) - - const test = some(1, 2) - }) - - test('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 - } - }) - - 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('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') - }) - - test('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] - - expectTypeOf(p1).toEqualTypeOf<[State, number?]>() - - const result = selectTest({ counter1: 1, counter2: 2 }, 42) - }) - - test('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?') - }) - - test('issue555', () => { - 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) - }) -}) From c91080547e9f8017a5381a3cd9e38ea16afabd41 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 12:23:59 -0600 Subject: [PATCH 34/60] Make `describe` titles more consistent across type tests --- type-tests/argsMemoize.test-d.ts | 2 +- type-tests/createSelector.withTypes.test-d.ts | 2 +- type-tests/createStructuredSelector.withTypes.test-d.ts | 2 +- type-tests/deepNesting.test-d.ts | 7 +++---- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/type-tests/argsMemoize.test-d.ts b/type-tests/argsMemoize.test-d.ts index 47d90ecb6..d5278645a 100644 --- a/type-tests/argsMemoize.test-d.ts +++ b/type-tests/argsMemoize.test-d.ts @@ -23,7 +23,7 @@ const state: RootState = { ] } -describe('memoize and argsMemoize', () => { +describe('type tests', () => { test('Override Only Memoize In createSelector', () => { const selectorDefaultSeparateInlineArgs = createSelector( (state: RootState) => state.todos, diff --git a/type-tests/createSelector.withTypes.test-d.ts b/type-tests/createSelector.withTypes.test-d.ts index 26c4d8e88..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', () => { diff --git a/type-tests/createStructuredSelector.withTypes.test-d.ts b/type-tests/createStructuredSelector.withTypes.test-d.ts index 3c461dbce..98d3aba71 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() diff --git a/type-tests/deepNesting.test-d.ts b/type-tests/deepNesting.test-d.ts index 5ba856d90..8460c2f10 100644 --- a/type-tests/deepNesting.test-d.ts +++ b/type-tests/deepNesting.test-d.ts @@ -19,9 +19,9 @@ const state: RootState = { type AnyFunction = (...args: any[]) => any -describe('deep nesting #525', () => { - test('Deep Nesting First And Second createSelector Overload', () => { - // Verify more than 12 selectors are accepted +describe('type tests', () => { + test('issue #525: verify more than 12 selectors are accepted', () => { + // https://github.com/reduxjs/reselect/issues/525 const selectTodos = (state: RootState) => state.todos @@ -432,5 +432,4 @@ describe('deep nesting #525', () => { } ) }) - }) From 2ad733df7ebffc9fd0b7934f86d1bfdc3740cf0d Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 9 Feb 2024 12:27:36 -0600 Subject: [PATCH 35/60] De-duplicate `AnyFunction` definitions --- test/examples.test.ts | 3 ++- type-tests/createSelectorCreator.test-d.ts | 3 ++- type-tests/deepNesting.test-d.ts | 3 +-- type-tests/lruMemoize.test-d.ts | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) 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/type-tests/createSelectorCreator.test-d.ts b/type-tests/createSelectorCreator.test-d.ts index f34632826..82b8894d7 100644 --- a/type-tests/createSelectorCreator.test-d.ts +++ b/type-tests/createSelectorCreator.test-d.ts @@ -1,3 +1,4 @@ +import type { AnyFunction } from '@internal/types' import lodashMemoize from 'lodash/memoize' import memoizeOne from 'memoize-one' import microMemoize from 'micro-memoize' @@ -100,7 +101,7 @@ describe('type tests', () => { test('custom memoization option types', () => { const customMemoize = ( - f: (...args: any[]) => any, + f: AnyFunction, a: string, b: number, c: boolean diff --git a/type-tests/deepNesting.test-d.ts b/type-tests/deepNesting.test-d.ts index 8460c2f10..b4c92d779 100644 --- a/type-tests/deepNesting.test-d.ts +++ b/type-tests/deepNesting.test-d.ts @@ -1,3 +1,4 @@ +import type { AnyFunction } from '@internal/types' import type { Cache } from 'micro-memoize' import microMemoize from 'micro-memoize' import { createSelector, lruMemoize } from 'reselect' @@ -17,8 +18,6 @@ const state: RootState = { ] } -type AnyFunction = (...args: any[]) => any - describe('type tests', () => { test('issue #525: verify more than 12 selectors are accepted', () => { // https://github.com/reduxjs/reselect/issues/525 diff --git a/type-tests/lruMemoize.test-d.ts b/type-tests/lruMemoize.test-d.ts index 3b3e69ed0..74d9f97b2 100644 --- a/type-tests/lruMemoize.test-d.ts +++ b/type-tests/lruMemoize.test-d.ts @@ -1,3 +1,4 @@ +import type { AnyFunction } from '@internal/types' import { groupBy, isEqual } from 'lodash' import { createSelectorCreator, @@ -33,7 +34,7 @@ describe('type tests', () => { test('issue #384', () => { // https://github.com/reduxjs/reselect/issues/384 - function multiArgMemoize any>( + function multiArgMemoize( func: F, a: number, b: string, From b67abce6688d64d7ee26d94b47a9f47e672d9dd2 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Wed, 21 Feb 2024 12:06:29 -0600 Subject: [PATCH 36/60] Fix type issues in `scripts/writeGitVersion.mjs` --- scripts/writeGitVersion.mjs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) 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)) From 8e0abec3552dc12d0ed6629342e92e6421a39efa Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Wed, 21 Feb 2024 12:29:51 -0600 Subject: [PATCH 37/60] Rename `setup.vitest.ts` to `setup.ts` --- test/{setup.vitest.ts => setup.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{setup.vitest.ts => setup.ts} (100%) 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 From c67ae78ee92c9acf660d6964d6664382271894a9 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Wed, 21 Feb 2024 12:30:28 -0600 Subject: [PATCH 38/60] Change `setupFiles` to `['test/setup.ts']` --- vitest.config.mts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vitest.config.mts b/vitest.config.mts index 99ac2dbfd..6cc8f49aa 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -9,7 +9,7 @@ const __dirname = path.dirname(__filename) export default defineConfig({ test: { globals: true, - setupFiles: ['test/setup.vitest.ts'], + setupFiles: ['test/setup.ts'], alias: { reselect: path.join(__dirname, 'src/index.ts'), // @remap-prod-remove-line From 273f1630856733371b4b76566040de7a7612ff77 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Wed, 21 Feb 2024 12:39:54 -0600 Subject: [PATCH 39/60] Replace references of `typescript_test` to `type-tests` --- .eslintrc | 2 +- .gitignore | 3 --- package.json | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) 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/.gitignore b/.gitignore index 9bd845cd0..9b87ac752 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/ diff --git a/package.json b/package.json index ca94768aa..e122d2fdf 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "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", + "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", From 2c06cc342f5fb1697007c806bc78bb59654966a4 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Sat, 24 Feb 2024 03:57:47 -0600 Subject: [PATCH 40/60] Remove Node ESM setup from `vitest.config.mts` --- vitest.config.mts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/vitest.config.mts b/vitest.config.mts index 6cc8f49aa..daab3212e 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -1,20 +1,14 @@ -import path from 'node:path' -import { fileURLToPath } from 'node:url' import { defineConfig } from 'vitest/config' -// No __dirname under Node ESM -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) - export default defineConfig({ test: { globals: true, setupFiles: ['test/setup.ts'], alias: { - reselect: path.join(__dirname, 'src/index.ts'), // @remap-prod-remove-line + reselect: new URL('src/index.ts', import.meta.url).pathname, // @remap-prod-remove-line // 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 } } }) From fd8456c5d1769df4b0a8564a6ce3b0148fabe051 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Tue, 17 Sep 2024 03:42:15 -0500 Subject: [PATCH 41/60] Provide the correct `tsconfig` file to `tsup` --- tsup.config.ts | 3 +++ 1 file changed, 3 insertions(+) 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 } From 8db970b0cf79e1450cf67dd7b6bfd2d4c9551769 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Mon, 29 Apr 2024 10:46:55 -0500 Subject: [PATCH 42/60] Add `yalc` to `.gitignore` --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9b87ac752..71f5638d9 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,7 @@ website/.yarn/ docs/examples/**/*.js docs/examples/**/*.jsx -tsconfig.vitest-temp.json \ No newline at end of file +tsconfig.vitest-temp.json + +.yalc +yalc.lock From dae55301ee18079218a98765ff57b160fddd9d57 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 8 Feb 2024 11:42:38 -0600 Subject: [PATCH 43/60] Run both runtime and type tests against the `dist` folder during CI --- .github/workflows/build-and-test-types.yml | 84 ++++++++++++++++------ vitest.config.mts | 5 +- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build-and-test-types.yml b/.github/workflows/build-and-test-types.yml index 39c847487..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,16 +81,16 @@ 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 tsconfig.base.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 tsc --version yarn type-tests 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/vitest.config.mts b/vitest.config.mts index daab3212e..b23484f26 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -5,7 +5,10 @@ export default defineConfig({ globals: true, setupFiles: ['test/setup.ts'], alias: { - reselect: new URL('src/index.ts', import.meta.url).pathname, // @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': new URL('src', import.meta.url).pathname From c44cc25fe79720985b87be373fd28e23b96826de Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 10 May 2024 03:42:09 -0500 Subject: [PATCH 44/60] Remove dead code from `computationComparisons.spec.tsx` - There were multiple `store.dispatch` calls that were not needed. These were removed to clean up the test file and speed up execution of tests. --- test/computationComparisons.spec.tsx | 44 ---------------------------- 1 file changed, 44 deletions(-) diff --git a/test/computationComparisons.spec.tsx b/test/computationComparisons.spec.tsx index 472080f05..6c7028b9b 100644 --- a/test/computationComparisons.spec.tsx +++ b/test/computationComparisons.spec.tsx @@ -193,51 +193,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 - // }) }) }) From eeb7c5851cff1e3a2b1ed7107b3a167b53d77071 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 10 May 2024 03:43:49 -0500 Subject: [PATCH 45/60] Remove unnecessary test from `computationComparisons.spec.tsx` - This was done mainly to speed up executions of unit tests. --- test/computationComparisons.spec.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/computationComparisons.spec.tsx b/test/computationComparisons.spec.tsx index 6c7028b9b..61b84ff7d 100644 --- a/test/computationComparisons.spec.tsx +++ b/test/computationComparisons.spec.tsx @@ -18,15 +18,6 @@ import type { RootState, Todo } from './testUtils' import { addTodo, 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(() => { From 1145ebd74c831d63cfbeb1037ad6d2ca1b396e34 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 10 May 2024 04:00:40 -0500 Subject: [PATCH 46/60] Remove unnecessary `async` keyword --- test/computationComparisons.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/computationComparisons.spec.tsx b/test/computationComparisons.spec.tsx index 61b84ff7d..c08527fb8 100644 --- a/test/computationComparisons.spec.tsx +++ b/test/computationComparisons.spec.tsx @@ -166,7 +166,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() From c4262721a40ae1bf37262bea063c6e8b39b9ffad Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 10 May 2024 05:28:58 -0500 Subject: [PATCH 47/60] Fix some issues that were left over from the switch to `weakMapMemoize` - Looks like some of the code in `computationComparisons.spec.tsx` wasn't properly updated after we switched the default memoization function from `lruMemoize` to `weakMapMemoize`. These have been updated to their correct implementations. - Correct residual naming inconsistencies from the previous `defaultMemoize` to `lruMemoize` renaming. All references to `default` have been updated to `lru`. --- test/computationComparisons.spec.tsx | 49 +++++++++++++++------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/test/computationComparisons.spec.tsx b/test/computationComparisons.spec.tsx index c08527fb8..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,7 +15,7 @@ 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', () => { let store: ReturnType @@ -28,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, { @@ -76,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 } } ) @@ -102,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 }: { @@ -151,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], From b75daaa27ea92fc312edd9e845b00892d6b02ce8 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 10 May 2024 13:58:58 -0500 Subject: [PATCH 48/60] Disable `watch` by default --- vitest.config.mts | 1 + 1 file changed, 1 insertion(+) diff --git a/vitest.config.mts b/vitest.config.mts index b23484f26..f0d43ab31 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -2,6 +2,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { + watch: false, globals: true, setupFiles: ['test/setup.ts'], alias: { From bc1bee6f023c6d982b60101733a08ca4d03245a8 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 16 May 2024 13:27:13 -0500 Subject: [PATCH 49/60] Migrate type tests in `lruMemoize.test-d.ts` to Vitest --- type-tests/lruMemoize.test-d.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/type-tests/lruMemoize.test-d.ts b/type-tests/lruMemoize.test-d.ts index 74d9f97b2..f1543941b 100644 --- a/type-tests/lruMemoize.test-d.ts +++ b/type-tests/lruMemoize.test-d.ts @@ -12,9 +12,9 @@ describe('type tests', () => { const memoized = lruMemoize(func) - const ret0: number = memoized('42') - // @ts-expect-error - const ret1: string = memoized('42') + expectTypeOf(memoized('42')).toBeNumber() + + expectTypeOf(memoized('42')).not.toBeString() const memoized2 = lruMemoize( (str: string, arr: string[]): { str: string; arr: string[] } => ({ @@ -27,8 +27,10 @@ describe('type tests', () => { ) const ret2 = memoized2('', ['1', '2']) - const str: string = ret2.str - const arr: string[] = ret2.arr + + expectTypeOf(ret2.str).toBeString() + + expectTypeOf(ret2.arr).items.toBeString() }) test('issue #384', () => { @@ -40,8 +42,7 @@ describe('type tests', () => { b: string, equalityCheck = referenceEqualityCheck ): F { - // @ts-ignore - return () => {} + return func } interface Transaction { @@ -49,12 +50,14 @@ describe('type tests', () => { } 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( + expectTypeOf(createSelectorCreator).toBeCallableWith( lruMemoize, collectionsEqual ) @@ -70,8 +73,9 @@ describe('type tests', () => { (state: { foo: string }) => state.foo, foo => `${foo}!` ) + // error is not applicable anymore - select.clearCache() + expectTypeOf(select.clearCache).toBeFunction() const createMultiMemoizeArgSelector2 = createSelectorCreator( multiArgMemoize, @@ -80,7 +84,7 @@ describe('type tests', () => { referenceEqualityCheck ) - const groupTransactionsByLabel = lruMemoize( + expectTypeOf(lruMemoize).toBeCallableWith( (transactions: Transaction[]) => groupBy(transactions, item => item.transactionId), collectionsEqual From fcec4783c47ae98877a90b70308aac09f8fa2ed1 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 16 May 2024 13:48:45 -0500 Subject: [PATCH 50/60] Migrate some assertions in `createSelectorCreator.test-d.ts` to Vitest --- type-tests/createSelectorCreator.test-d.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/type-tests/createSelectorCreator.test-d.ts b/type-tests/createSelectorCreator.test-d.ts index 82b8894d7..2ee0f6d3e 100644 --- a/type-tests/createSelectorCreator.test-d.ts +++ b/type-tests/createSelectorCreator.test-d.ts @@ -70,13 +70,13 @@ describe('type tests', () => { (state: { foo: string }) => state.foo, foo => foo ) - const value: string = selector({ foo: 'fizz' }) - // @ts-expect-error - selector({ foo: 'fizz' }, { bar: 42 }) + expectTypeOf(selector({ foo: 'fizz' })).toBeString() + + expectTypeOf(selector).parameter(1).not.toMatchTypeOf({ bar: 42 }) // clearCache should exist because of lruMemoize - selector.clearCache() + expectTypeOf(selector.clearCache).toBeFunction() const parametric = defaultCreateSelector( (state: { foo: string }) => state.foo, @@ -88,8 +88,10 @@ describe('type tests', () => { parametric({ foo: 'fizz' }) const ret = parametric({ foo: 'fizz' }, { bar: 42 }) - const foo: string = ret.foo - const bar: number = ret.bar + + expectTypeOf(ret.foo).toBeString() + + expectTypeOf(ret.bar).toBeNumber() // @ts-expect-error createSelectorCreator(lruMemoize, 1) From 58daa41c52d4a25d3ce6c8767d62c4ae08e443dc Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 16 May 2024 15:47:37 -0500 Subject: [PATCH 51/60] Migrate some assertions in `createSelector.test-d.ts` to Vitest --- type-tests/createSelector.test-d.ts | 50 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/type-tests/createSelector.test-d.ts b/type-tests/createSelector.test-d.ts index 431499c2e..d2e827f8e 100644 --- a/type-tests/createSelector.test-d.ts +++ b/type-tests/createSelector.test-d.ts @@ -31,17 +31,17 @@ describe('type tests', () => { foo => foo ) - const res = selector.resultFunc('test') - selector.recomputations() - selector.resetRecomputations() + expectTypeOf(selector.resultFunc).toBeCallableWith('test') - const foo: string = selector({ foo: 'bar' }) + expectTypeOf(selector.recomputations).toBeFunction() - // @ts-expect-error - selector({ foo: 'bar' }, { prop: 'value' }) + expectTypeOf(selector.resetRecomputations).toBeFunction() - // @ts-expect-error - const num: number = selector({ foo: 'bar' }) + expectTypeOf(selector({ foo: 'bar' })).toBeString() + + expectTypeOf(selector).parameters.not.toHaveProperty('1') + + expectTypeOf(selector({ foo: 'bar' })).not.toBeNumber() // allows heterogeneous parameter type input selectors createSelector( @@ -73,13 +73,11 @@ describe('type tests', () => { const selector = createSelector((state: State) => state.bar, subSelector) - // @ts-expect-error - selector({ foo: '' }) + expectTypeOf(selector).parameter(0).not.toMatchTypeOf({ foo: '' }) - // @ts-expect-error - const n: number = selector({ bar: { foo: '' } }) + expectTypeOf(selector({ bar: { foo: '' } })).not.toBeNumber() - const s: string = selector({ bar: { foo: '' } }) + expectTypeOf(selector({ bar: { foo: '' } })).toBeString() }) test('connect', () => { @@ -89,10 +87,9 @@ describe('type tests', () => { foo => ({ foo }) ) )(props => { - // @ts-expect-error - props.bar + expectTypeOf(props).not.toHaveProperty('bar') - const foo: string = props.foo + expectTypeOf(props).toHaveProperty('foo').toBeString() }) const selector2 = createSelector( @@ -102,17 +99,20 @@ describe('type tests', () => { ) 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 + expectTypeOf(props).toHaveProperty('foo').toBeString() + + expectTypeOf(props).toHaveProperty('bar').toBeNumber() + + expectTypeOf(props).toHaveProperty('baz').toBeNumber() + + expectTypeOf(props).not.toHaveProperty('fizz') }) - connected({ bar: 42 }) + expectTypeOf(connected).toBeCallableWith({ bar: 42 }) - // @ts-expect-error - connected({ bar: 42, baz: 123 }) + expectTypeOf(connected) + .parameter(0) + .not.toMatchTypeOf({ bar: 42, baz: 123 }) }) test('invalid type in combiner', () => { @@ -224,7 +224,7 @@ describe('type tests', () => { } ) - const res1 = selector1({ + expectTypeOf(selector1).toBeCallableWith({ testString: 'a', testNumber: 42, testBoolean: true, From 6433a6ab47a511d75bbe2705b989a5700467fb57 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 16 May 2024 16:15:20 -0500 Subject: [PATCH 52/60] Migrate some assertions in `createSelector.test-d.ts` to Vitest --- type-tests/createSelector.test-d.ts | 133 +++++++++++++++------------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/type-tests/createSelector.test-d.ts b/type-tests/createSelector.test-d.ts index d2e827f8e..ea8ceb15a 100644 --- a/type-tests/createSelector.test-d.ts +++ b/type-tests/createSelector.test-d.ts @@ -243,8 +243,10 @@ describe('type tests', () => { selector({ foo: 'fizz' }, { bar: 'baz' }) const ret = selector({ foo: 'fizz' }, { bar: 42 }) - const foo: string = ret.foo - const bar: number = ret.bar + + expectTypeOf(ret).toHaveProperty('foo').toBeString() + + expectTypeOf(ret).toHaveProperty('bar').toBeNumber() const selector2 = createSelector( (state: State) => state.foo, @@ -263,7 +265,7 @@ describe('type tests', () => { }) ) - selector2({ foo: 'fizz' }, { bar: 42 }) + expectTypeOf(selector2).toBeCallableWith({ foo: 'fizz' }, { bar: 42 }) const selector3 = createSelector( (s: State) => s.foo, @@ -274,8 +276,7 @@ describe('type tests', () => { } ) - // @ts-expect-error - selector3({ foo: 'fizz' }, 42) + expectTypeOf(selector3).parameter(1).toBeNever() const selector4 = createSelector( (s: State, val: number) => s.foo, @@ -285,7 +286,7 @@ describe('type tests', () => { } ) - selector4({ foo: 'fizz' }, 42) + expectTypeOf(selector4).toBeCallableWith({ foo: 'fizz' }, 42) }) test('array argument', () => { @@ -299,9 +300,12 @@ describe('type tests', () => { ) const ret = selector({ foo: 'fizz' }, { bar: 42 }) - const foo1: string = ret.foo1 - const foo2: string = ret.foo2 - const bar: number = ret.bar + + expectTypeOf(ret).toHaveProperty('foo1').toBeString() + + expectTypeOf(ret).toHaveProperty('foo2').toBeString() + + expectTypeOf(ret).toHaveProperty('bar').toBeNumber() // @ts-expect-error createSelector([(state: { foo: string }) => state.foo]) @@ -424,21 +428,29 @@ describe('type tests', () => { { 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 + + 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') } - // @ts-expect-error - selector2({ foo: 'fizz' }, { bar: 42 }) + expectTypeOf(selector2).parameters.not.toHaveProperty('1') const parametric = createSelector( [ @@ -500,17 +512,26 @@ describe('type tests', () => { { 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 + + 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') } }) @@ -526,9 +547,9 @@ describe('type tests', () => { (state: State, arg: string) => arg, (state: State, arg: number) => arg, baz => { - const baz1: boolean = baz - // @ts-expect-error - const baz2: number = baz + expectTypeOf(baz).toBeBoolean() + + expectTypeOf(baz).not.toBeNumber() } ) @@ -571,7 +592,8 @@ describe('type tests', () => { selector4({} as State) // @ts-expect-error selector4({} as State, 'blach') - selector4({} as State, 'blach', 4) + + expectTypeOf(selector4).toBeCallableWith({} as State, 'blach', 4) // as above but a unknown 2nd argument const selector5 = createSelector( @@ -584,36 +606,19 @@ describe('type tests', () => { 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) + + 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, - // eslint-disable-next-line @typescript-eslint/no-inferrable-types - prefix: string = 'a' - ) => prefix + state.foo, + (state: State, prefix: string = 'a') => prefix + state.foo, (str: string) => str ) - selector7({} as State) - selector7({} as State, 'blach') + expectTypeOf(selector7).toBeCallableWith({} as State) + + expectTypeOf(selector7).toBeCallableWith({} as State, 'blach') + // @ts-expect-error wrong type selector7({} as State, 1) @@ -624,9 +629,11 @@ describe('type tests', () => { // @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) + expectTypeOf(selector8).toBeCallableWith({} as State, 'blach') + + expectTypeOf(selector8).toBeCallableWith({} as State, 2) }) test('dynamic array argument', () => { From cbf01c473420c1df5d70c812f5c64e31e3d366e2 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 31 May 2024 13:59:55 -0500 Subject: [PATCH 53/60] Migrate the rest of the type tests in `argsMemoize.test-d.ts` to Vitest --- type-tests/argsMemoize.test-d.ts | 493 +++++++++++++++++++++++-------- 1 file changed, 369 insertions(+), 124 deletions(-) diff --git a/type-tests/argsMemoize.test-d.ts b/type-tests/argsMemoize.test-d.ts index d5278645a..378a990bd 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: { @@ -30,31 +30,37 @@ describe('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { 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('type tests', () => { argsMemoize: weakMapMemoize, memoizeOptions: { equalityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b, maxSize: 2 }, @@ -243,6 +276,7 @@ describe('type tests', () => { 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('type tests', () => { { 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('type tests', () => { argsMemoizeOptions: [{ maxSize: 2 }] } ) + const selectorWeakMapSeparateInlineArgsWithMemoizeOptions4 = createSelectorLruMemoize( // @ts-expect-error @@ -273,10 +307,11 @@ describe('type tests', () => { { 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('type tests', () => { argsMemoize: weakMapMemoize, memoizeOptions: [{ isPromise: false }], argsMemoizeOptions: [] - // argsMemoizeOptions: (a, b) => a === b } ) + const selectorWeakMapSeparateInlineArgsWithMemoizeOptions6 = createSelectorLruMemoize( (state: RootState) => state.todos, @@ -299,27 +334,33 @@ describe('type tests', () => { 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('type tests', () => { 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,10 +389,10 @@ describe('type tests', () => { 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) @@ -360,23 +403,42 @@ describe('type tests', () => { expectTypeOf(selectorMicroMemoize).parameter(0).not.toBeNever() // Checking existence of fields related to `argsMemoize` - expectTypeOf(selectorMicroMemoize).parameter(0).not.toBeNever() - 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 expectTypeOf(selectorMicroMemoize.dependencies).toEqualTypeOf< [ @@ -428,25 +490,53 @@ describe('type tests', () => { 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 expectTypeOf(selectorMicroMemoizeOverridden.dependencies).toEqualTypeOf< @@ -501,25 +591,56 @@ describe('type tests', () => { .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 expectTypeOf( @@ -573,7 +694,7 @@ describe('type tests', () => { memoizeOptions: { isPromise: false, resultEqualityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b }, argsMemoizeOptions: { resultEqualityCheck: (a, b) => a === b } @@ -599,24 +720,56 @@ describe('type tests', () => { .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 expectTypeOf( @@ -680,24 +833,55 @@ describe('type tests', () => { .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 @@ -755,7 +939,7 @@ describe('type tests', () => { argsMemoize: lruMemoize, memoizeOptions: { equalityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b, maxSize: 2 }, @@ -774,7 +958,7 @@ describe('type tests', () => { memoizeOptions: [ { equalityCheck: - // @ts-expect-error + // @ts-expect-error implicit any (a, b) => a === b, maxSize: 2 } @@ -825,22 +1009,37 @@ describe('type tests', () => { >() // 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 @@ -907,26 +1106,63 @@ describe('type tests', () => { .parameter(0) .not.toBeNever() - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.resultFunc - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.clearCache() - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.cache - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.fn - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.isMemoized - // @ts-expect-error - selectorMicroMemoizeArgsMemoizeOptionsFallbackToDefault.options + 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 expectTypeOf( @@ -995,10 +1231,16 @@ describe('type tests', () => { { // @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. ) @@ -1010,6 +1252,9 @@ describe('type tests', () => { todos => todos.map(t => t.id), { memoize: autotrackMemoize } ) - selector.memoizedResultFunc.clearCache + + expectTypeOf(selector.memoizedResultFunc) + .toHaveProperty('clearCache') + .toBeFunction() }) }) From d8f569c80a64d09925e7de8e61bd54df66931148 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Tue, 20 Aug 2024 19:34:17 -0500 Subject: [PATCH 54/60] Set `pool` to `threads` for performance tests --- vitest.config.mts | 1 + 1 file changed, 1 insertion(+) diff --git a/vitest.config.mts b/vitest.config.mts index f0d43ab31..7b527ac63 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -2,6 +2,7 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { + pool: 'threads', watch: false, globals: true, setupFiles: ['test/setup.ts'], From a6a5ad90c9cd38d40d97f95cc6b7b9b4006091f1 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 12 Sep 2024 03:36:46 -0500 Subject: [PATCH 55/60] Remove `esbuild` from `resolutions` field --- package.json | 3 - yarn.lock | 774 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 512 insertions(+), 265 deletions(-) diff --git a/package.json b/package.json index e122d2fdf..990a12b7e 100644 --- a/package.json +++ b/package.json @@ -84,8 +84,5 @@ "typescript": "^5.8.2", "vitest": "^1.6.0" }, - "resolutions": { - "esbuild": "0.23.0" - }, "packageManager": "yarn@4.4.1" } diff --git a/yarn.lock b/yarn.lock index c9f4677c9..cf9571ea5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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 @@ -102,182 +102,350 @@ __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.21.5": + version: 0.21.5 + resolution: "@esbuild/aix-ppc64@npm:0.21.5" 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/aix-ppc64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/aix-ppc64@npm:0.25.2" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm64@npm:0.21.5" 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-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/android-arm64@npm:0.25.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm@npm:0.21.5" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/android-arm@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/android-x64@npm:0.21.5" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/android-x64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-arm64@npm:0.21.5" 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-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/darwin-arm64@npm:0.25.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-x64@npm:0.21.5" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/darwin-x64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-arm64@npm:0.21.5" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/freebsd-arm64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-x64@npm:0.21.5" 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/freebsd-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/freebsd-x64@npm:0.25.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm64@npm:0.21.5" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-arm64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm@npm:0.21.5" 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-arm@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-arm@npm:0.25.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ia32@npm:0.21.5" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-ia32@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-loong64@npm:0.21.5" 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-loong64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-loong64@npm:0.25.2" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-mips64el@npm:0.21.5" 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-mips64el@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-mips64el@npm:0.25.2" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ppc64@npm:0.21.5" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-ppc64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-riscv64@npm:0.21.5" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-riscv64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-s390x@npm:0.21.5" 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-s390x@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-s390x@npm:0.25.2" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-x64@npm:0.21.5" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-x64@npm:0.25.2" 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.2": + version: 0.25.2 + resolution: "@esbuild/netbsd-arm64@npm:0.25.2" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/netbsd-x64@npm:0.21.5" 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/netbsd-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/netbsd-x64@npm:0.25.2" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/openbsd-arm64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/openbsd-x64@npm:0.21.5" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/openbsd-x64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/sunos-x64@npm:0.21.5" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/sunos-x64@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-arm64@npm:0.21.5" 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-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/win32-arm64@npm:0.25.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-ia32@npm:0.21.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/win32-ia32@npm:0.25.2" 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.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-x64@npm:0.21.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/win32-x64@npm:0.25.2" 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.5.1 + resolution: "@eslint-community/eslint-utils@npm:4.5.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/336b85150cf1828cba5b1fcf694233b947e635654c33aa2c1692dc9522d617218dff5abf3aaa6410b92fcb7fd1f0bf5393ec5b588987ac8835860465f8808ec5 languageName: node linkType: hard @@ -487,135 +655,142 @@ __metadata: 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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-android-arm64@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.39.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.39.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.39.0": + version: 4.39.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.39.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -664,10 +839,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 @@ -703,11 +878,11 @@ __metadata: linkType: hard "@types/node@npm:*": - version: 22.13.10 - resolution: "@types/node@npm:22.13.10" + version: 22.14.0 + resolution: "@types/node@npm:22.14.0" dependencies: - undici-types: "npm:~6.20.0" - checksum: 10/57dc6a5e0110ca9edea8d7047082e649fa7fa813f79e4a901653b9174141c622f4336435648baced5b38d9f39843f404fa2d8d7a10981610da26066bc8caab48 + undici-types: "npm:~6.21.0" + checksum: 10/d0669a8a37a18532c886ccfa51eb3fe1e46088deb4d3d27ebcd5d7d68bd6343ad1c7a3fcb85164780a57629359c33a6c917ecff748ea232bceac7692acc96537 languageName: node linkType: hard @@ -719,28 +894,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 @@ -1447,9 +1622,9 @@ __metadata: 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 @@ -1882,34 +2057,115 @@ __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.21.3": + version: 0.21.5 + resolution: "esbuild@npm:0.21.5" + dependencies: + "@esbuild/aix-ppc64": "npm:0.21.5" + "@esbuild/android-arm": "npm:0.21.5" + "@esbuild/android-arm64": "npm:0.21.5" + "@esbuild/android-x64": "npm:0.21.5" + "@esbuild/darwin-arm64": "npm:0.21.5" + "@esbuild/darwin-x64": "npm:0.21.5" + "@esbuild/freebsd-arm64": "npm:0.21.5" + "@esbuild/freebsd-x64": "npm:0.21.5" + "@esbuild/linux-arm": "npm:0.21.5" + "@esbuild/linux-arm64": "npm:0.21.5" + "@esbuild/linux-ia32": "npm:0.21.5" + "@esbuild/linux-loong64": "npm:0.21.5" + "@esbuild/linux-mips64el": "npm:0.21.5" + "@esbuild/linux-ppc64": "npm:0.21.5" + "@esbuild/linux-riscv64": "npm:0.21.5" + "@esbuild/linux-s390x": "npm:0.21.5" + "@esbuild/linux-x64": "npm:0.21.5" + "@esbuild/netbsd-x64": "npm:0.21.5" + "@esbuild/openbsd-x64": "npm:0.21.5" + "@esbuild/sunos-x64": "npm:0.21.5" + "@esbuild/win32-arm64": "npm:0.21.5" + "@esbuild/win32-ia32": "npm:0.21.5" + "@esbuild/win32-x64": "npm:0.21.5" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10/d2ff2ca84d30cce8e871517374d6c2290835380dc7cd413b2d49189ed170d45e407be14de2cb4794cf76f75cf89955c4714726ebd3de7444b3046f5cab23ab6b + languageName: node + linkType: hard + +"esbuild@npm:^0.25.0": + version: 0.25.2 + resolution: "esbuild@npm:0.25.2" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.2" + "@esbuild/android-arm": "npm:0.25.2" + "@esbuild/android-arm64": "npm:0.25.2" + "@esbuild/android-x64": "npm:0.25.2" + "@esbuild/darwin-arm64": "npm:0.25.2" + "@esbuild/darwin-x64": "npm:0.25.2" + "@esbuild/freebsd-arm64": "npm:0.25.2" + "@esbuild/freebsd-x64": "npm:0.25.2" + "@esbuild/linux-arm": "npm:0.25.2" + "@esbuild/linux-arm64": "npm:0.25.2" + "@esbuild/linux-ia32": "npm:0.25.2" + "@esbuild/linux-loong64": "npm:0.25.2" + "@esbuild/linux-mips64el": "npm:0.25.2" + "@esbuild/linux-ppc64": "npm:0.25.2" + "@esbuild/linux-riscv64": "npm:0.25.2" + "@esbuild/linux-s390x": "npm:0.25.2" + "@esbuild/linux-x64": "npm:0.25.2" + "@esbuild/netbsd-arm64": "npm:0.25.2" + "@esbuild/netbsd-x64": "npm:0.25.2" + "@esbuild/openbsd-arm64": "npm:0.25.2" + "@esbuild/openbsd-x64": "npm:0.25.2" + "@esbuild/sunos-x64": "npm:0.25.2" + "@esbuild/win32-arm64": "npm:0.25.2" + "@esbuild/win32-ia32": "npm:0.25.2" + "@esbuild/win32-x64": "npm:0.25.2" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -1945,6 +2201,8 @@ __metadata: optional: true "@esbuild/linux-x64": optional: true + "@esbuild/netbsd-arm64": + optional: true "@esbuild/netbsd-x64": optional: true "@esbuild/openbsd-arm64": @@ -1961,7 +2219,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/d3d91bf9ca73ba33966fc54cabb321eca770a5e2ff5b34d67e4235c94560cfd881803e39fcaa31d842579d10600da5201c5f597f8438679f6db856f75ded7124 + checksum: 10/3b16423d33e0c05078b38bfe88e1b2125164a6b8dccfd06db8698766e54406f3299de8a74e3ce818f1d5a9c8bf993aa4d27a5716c39580eb80bd92d52ccf34d3 languageName: node linkType: hard @@ -2437,7 +2695,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: @@ -3463,12 +3721,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 @@ -3512,11 +3769,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 +3799,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 @@ -3627,13 +3884,14 @@ __metadata: linkType: hard "object.entries@npm:^1.1.8": - version: 1.1.8 - resolution: "object.entries@npm:1.1.8" + 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 @@ -3858,9 +4116,9 @@ __metadata: linkType: hard "pirates@npm:^4.0.1": - version: 4.0.6 - resolution: "pirates@npm:4.0.6" - checksum: 10/d02dda76f4fec1cbdf395c36c11cf26f76a644f9f9a1bfa84d3167d0d3154d5289aacc72677aa20d599bb4a6937a471de1b65c995e2aea2d8687cbcd7e43ea5f + version: 4.0.7 + resolution: "pirates@npm:4.0.7" + checksum: 10/2427f371366081ae42feb58214f04805d6b41d6b84d74480ebcc9e0ddbd7105a139f7c653daeaf83ad8a1a77214cf07f64178e76de048128fec501eab3305a96 languageName: node linkType: hard @@ -4314,41 +4572,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" + version: 4.39.0 + resolution: "rollup@npm:4.39.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.39.0" + "@rollup/rollup-android-arm64": "npm:4.39.0" + "@rollup/rollup-darwin-arm64": "npm:4.39.0" + "@rollup/rollup-darwin-x64": "npm:4.39.0" + "@rollup/rollup-freebsd-arm64": "npm:4.39.0" + "@rollup/rollup-freebsd-x64": "npm:4.39.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.39.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.39.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.39.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.39.0" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.39.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.39.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.39.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.39.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.39.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.39.0" + "@rollup/rollup-linux-x64-musl": "npm:4.39.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.39.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.39.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.39.0" + "@types/estree": "npm:1.0.7" fsevents: "npm:~2.3.2" dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -4377,6 +4625,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 +4643,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/1fd13b8cb874106727cc4241e7b09167b835247185f52a0ac0d4b302df6dd01feec32e53ee3fead757c0c033f8b15ae6f0e093854de1878ae9e5dee37ec52579 + checksum: 10/d3b106efb71cd501b71e3a56e3257ccad4d969a201d59aa2e74d9b91ad5f44c508ddebfbe3de82d4324e9b0977420d35d6cce8e45f784a91080acea66c1c1ce8 languageName: node linkType: hard @@ -4976,7 +5226,7 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.11": +"tinyglobby@npm:^0.2.11, tinyglobby@npm:^0.2.12": version: 0.2.12 resolution: "tinyglobby@npm:0.2.12" dependencies: @@ -5030,12 +5280,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.0 + resolution: "tr46@npm:5.1.0" dependencies: punycode: "npm:^2.3.1" - checksum: 10/29155adb167d048d3c95d181f7cb5ac71948b4e8f3070ec455986e1f34634acae50ae02a3c8d448121c3afe35b76951cd46ed4c128fd80264280ca9502237a3e + checksum: 10/2f0249354018432250bc31287f857cb7a73c43a1753b0ddccc97d140d261fe5deddeb1bf1d77afbdb29f867721f46238e3f32e97b473ba0c7e29bc5c34ccc08f languageName: node linkType: hard @@ -5227,10 +5477,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 +5529,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 @@ -5310,8 +5560,8 @@ __metadata: linkType: hard "vite@npm:^5.0.0": - version: 5.4.14 - resolution: "vite@npm:5.4.14" + version: 5.4.16 + resolution: "vite@npm:5.4.16" dependencies: esbuild: "npm:^0.21.3" fsevents: "npm:~2.3.3" @@ -5348,7 +5598,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10/ce382f4059eb6c939823b8f62163794752243755d84c71a4b73ad0f7d4d9f4c7a557a6ef4c78e0640f4bcf5ae5ec6b20c7ee4816419af3c81ba275f478b73468 + checksum: 10/c5010e3962b0a33d50b25296ae9c2f5a45b4b46977b67b9a4016918d932817bb8e46fa14b88d75f752641d4a89f1545966139b58b07dc2d6e3196250a0b239cd languageName: node linkType: hard @@ -5442,12 +5692,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 @@ -5673,8 +5923,8 @@ __metadata: linkType: hard "yocto-queue@npm:^1.0.0": - version: 1.2.0 - resolution: "yocto-queue@npm:1.2.0" - checksum: 10/6154113e60285f75c9d59c65056ea3842d3d5c999a4c692568155dcc5b9c038850374eae1f04507090eeee8129b8110d9c7259d1aa9fe323957fd46892b655fc + version: 1.2.1 + resolution: "yocto-queue@npm:1.2.1" + checksum: 10/0843d6c2c0558e5c06e98edf9c17942f25c769e21b519303a5c2adefd5b738c9b2054204dc856ac0cd9d134b1bc27d928ce84fd23c9e2423b7e013d5a6f50577 languageName: node linkType: hard From eefd5f014bb1285aee5c5fb825420ea57c0d9b77 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 12 Sep 2024 03:45:15 -0500 Subject: [PATCH 56/60] Silence `console` output by disabling `identityFunctionCheck` --- test/lruMemoize.test.ts | 1 + 1 file changed, 1 insertion(+) 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 } } From d9a350217d5914332af470ac80fef756646f075f Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Mon, 30 Dec 2024 20:06:29 -0600 Subject: [PATCH 57/60] Correct minor spelling issues --- test/perfComparisons.spec.ts | 2 +- test/reselect.spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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' } } From cb3779d0942044af06ee5b7440ddbf77a3f85faa Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Tue, 20 Aug 2024 19:23:09 -0500 Subject: [PATCH 58/60] Bump `vitest` to version 3.1.1 --- package.json | 2 +- yarn.lock | 797 ++++++++++++--------------------------------------- 2 files changed, 188 insertions(+), 611 deletions(-) diff --git a/package.json b/package.json index 990a12b7e..08407cf43 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "shelljs": "^0.8.5", "tsup": "^8.2.4", "typescript": "^5.8.2", - "vitest": "^1.6.0" + "vitest": "^3.1.1" }, "packageManager": "yarn@4.4.1" } diff --git a/yarn.lock b/yarn.lock index cf9571ea5..724c0c80f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -102,13 +102,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/aix-ppc64@npm:0.21.5" - conditions: os=aix & cpu=ppc64 - languageName: node - linkType: hard - "@esbuild/aix-ppc64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/aix-ppc64@npm:0.25.2" @@ -116,13 +109,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm64@npm:0.21.5" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/android-arm64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/android-arm64@npm:0.25.2" @@ -130,13 +116,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm@npm:0.21.5" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - "@esbuild/android-arm@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/android-arm@npm:0.25.2" @@ -144,13 +123,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-x64@npm:0.21.5" - conditions: os=android & cpu=x64 - languageName: node - linkType: hard - "@esbuild/android-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/android-x64@npm:0.25.2" @@ -158,13 +130,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-arm64@npm:0.21.5" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/darwin-arm64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/darwin-arm64@npm:0.25.2" @@ -172,13 +137,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-x64@npm:0.21.5" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - "@esbuild/darwin-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/darwin-x64@npm:0.25.2" @@ -186,13 +144,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-arm64@npm:0.21.5" - conditions: os=freebsd & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/freebsd-arm64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/freebsd-arm64@npm:0.25.2" @@ -200,13 +151,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-x64@npm:0.21.5" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/freebsd-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/freebsd-x64@npm:0.25.2" @@ -214,13 +158,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm64@npm:0.21.5" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/linux-arm64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-arm64@npm:0.25.2" @@ -228,13 +165,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm@npm:0.21.5" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - "@esbuild/linux-arm@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-arm@npm:0.25.2" @@ -242,13 +172,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ia32@npm:0.21.5" - conditions: os=linux & cpu=ia32 - languageName: node - linkType: hard - "@esbuild/linux-ia32@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-ia32@npm:0.25.2" @@ -256,13 +179,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-loong64@npm:0.21.5" - conditions: os=linux & cpu=loong64 - languageName: node - linkType: hard - "@esbuild/linux-loong64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-loong64@npm:0.25.2" @@ -270,13 +186,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-mips64el@npm:0.21.5" - conditions: os=linux & cpu=mips64el - languageName: node - linkType: hard - "@esbuild/linux-mips64el@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-mips64el@npm:0.25.2" @@ -284,13 +193,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ppc64@npm:0.21.5" - conditions: os=linux & cpu=ppc64 - languageName: node - linkType: hard - "@esbuild/linux-ppc64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-ppc64@npm:0.25.2" @@ -298,13 +200,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-riscv64@npm:0.21.5" - conditions: os=linux & cpu=riscv64 - languageName: node - linkType: hard - "@esbuild/linux-riscv64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-riscv64@npm:0.25.2" @@ -312,13 +207,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-s390x@npm:0.21.5" - conditions: os=linux & cpu=s390x - languageName: node - linkType: hard - "@esbuild/linux-s390x@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-s390x@npm:0.25.2" @@ -326,13 +214,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-x64@npm:0.21.5" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - "@esbuild/linux-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/linux-x64@npm:0.25.2" @@ -347,13 +228,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/netbsd-x64@npm:0.21.5" - conditions: os=netbsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/netbsd-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/netbsd-x64@npm:0.25.2" @@ -368,13 +242,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/openbsd-x64@npm:0.21.5" - conditions: os=openbsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/openbsd-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/openbsd-x64@npm:0.25.2" @@ -382,13 +249,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/sunos-x64@npm:0.21.5" - conditions: os=sunos & cpu=x64 - languageName: node - linkType: hard - "@esbuild/sunos-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/sunos-x64@npm:0.25.2" @@ -396,13 +256,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-arm64@npm:0.21.5" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/win32-arm64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/win32-arm64@npm:0.25.2" @@ -410,13 +263,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-ia32@npm:0.21.5" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - "@esbuild/win32-ia32@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/win32-ia32@npm:0.25.2" @@ -424,13 +270,6 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-x64@npm:0.21.5" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@esbuild/win32-x64@npm:0.25.2": version: 0.25.2 resolution: "@esbuild/win32-x64@npm:0.25.2" @@ -528,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" @@ -795,13 +625,6 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.27.8": - version: 0.27.8 - resolution: "@sinclair/typebox@npm:0.27.8" - checksum: 10/297f95ff77c82c54de8c9907f186076e715ff2621c5222ba50b8d40a170661c0c5242c763cba2a4791f0f91cb1d8ffa53ea1d7294570cf8cd4694c0e383e484d - languageName: node - linkType: hard - "@testing-library/dom@npm:^9.0.0": version: 9.3.4 resolution: "@testing-library/dom@npm:9.3.4" @@ -1099,57 +922,84 @@ __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.1": + version: 3.1.1 + resolution: "@vitest/expect@npm:3.1.1" dependencies: - "@vitest/spy": "npm:1.6.1" - "@vitest/utils": "npm:1.6.1" - chai: "npm:^4.3.10" - checksum: 10/8aa366cc629bba4170eadebf092de9f64b46592fde9455b070cb7616dcba54f03d479e5844da0ddadecbc19a4f781a0b0d72ab2275cfccca54fd51398ac1b5d5 + "@vitest/spy": "npm:3.1.1" + "@vitest/utils": "npm:3.1.1" + chai: "npm:^5.2.0" + tinyrainbow: "npm:^2.0.0" + checksum: 10/79754e35fb505f6ee9636e49f78961299b99b12cebf6fd7ea6455a05d9a9589a65fa5d4537a7b4f6b837a41988ab629a6ff76252a4a5accf77f9462dbf3570c8 languageName: node linkType: hard -"@vitest/runner@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/runner@npm:1.6.1" +"@vitest/mocker@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/mocker@npm:3.1.1" dependencies: - "@vitest/utils": "npm:1.6.1" - p-limit: "npm:^5.0.0" - pathe: "npm:^1.1.1" - checksum: 10/b3ee2cb7b80108c48505f71e291b7a70c819dc4c704c77d44beb722d641c5ef8e6f623e95a0259a3d0e8178d1b3559f426d03f13a3500420d1c2b8802e0128c4 + "@vitest/spy": "npm:3.1.1" + 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/18b72593071b4416b096c2c09899e9213804ec5e0fc90f6c5464ebd9645f34de9c2d0ecb09cbc7f3d44fbcf897fca2921ba114b185fc86a70050ccee1c6d6cc8 languageName: node linkType: hard -"@vitest/snapshot@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/snapshot@npm:1.6.1" +"@vitest/pretty-format@npm:3.1.1, @vitest/pretty-format@npm:^3.1.1": + version: 3.1.1 + resolution: "@vitest/pretty-format@npm:3.1.1" dependencies: - magic-string: "npm:^0.30.5" - pathe: "npm:^1.1.1" - pretty-format: "npm:^29.7.0" - checksum: 10/f78876503ac850ac3f0a0766133cd020d83c1e665711d4e4370f5f408051b8da7a6294882c549b00a90f03c4ca25b7c41893514a7d5f9f336e6a47ad533b4cb1 + tinyrainbow: "npm:^2.0.0" + checksum: 10/d1bc6a6c687d686194ef19ebc748894c543bc520d79db5e86d53ac97f004d13d5b364592a21e151031bf76bf8865ce25e60fc71cc02ca0d513d20bc0c600a63f languageName: node linkType: hard -"@vitest/spy@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/spy@npm:1.6.1" +"@vitest/runner@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/runner@npm:3.1.1" dependencies: - tinyspy: "npm:^2.2.0" - checksum: 10/55076c8dad8585c4d3923ec1e948e97746150d9d259a7b6045d8dd0e22babc631b22c31882c976c25b68cfbaf11d9d47fe0a77e68c3f1b8973b90c6b835becdb + "@vitest/utils": "npm:3.1.1" + pathe: "npm:^2.0.3" + checksum: 10/652a351e59d2f615f3b3de0bb47bfb7875117dd3e57a62c031d8f385614513dbe77847a39037aedb79818a3fde1d957bb82e2f3a5c74651d27721553ed8b4668 languageName: node linkType: hard -"@vitest/utils@npm:1.6.1": - version: 1.6.1 - resolution: "@vitest/utils@npm:1.6.1" +"@vitest/snapshot@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/snapshot@npm:3.1.1" 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.1" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + checksum: 10/517ad76c35bd55d2908349a9a5749f874927971c2d6f4ffb3a6f6345acb7a393fac4cc9778119a215caf9ee0c96c75dc27c9f9227a51bd3907c36da946652d43 + languageName: node + linkType: hard + +"@vitest/spy@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/spy@npm:3.1.1" + dependencies: + tinyspy: "npm:^3.0.2" + checksum: 10/2b2c8cb2f13fe4ea48779b91c69140c596c8fe3a3ef283ef8b19c025cfdb59a60db7c65a320c84fa28b26655877570860bb44bc2d0e99639d097a7e042e3c604 + languageName: node + linkType: hard + +"@vitest/utils@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/utils@npm:3.1.1" + dependencies: + "@vitest/pretty-format": "npm:3.1.1" + loupe: "npm:^3.1.3" + tinyrainbow: "npm:^2.0.0" + checksum: 10/05f28d3e6636966803d60d4867200d6a3a5b7bc2ebaf1583bc3d5a2fc024e024c4958237eca73e420349faf326a8f62c3ae00b2cc2edb42d601b79a759f21b8f languageName: node linkType: hard @@ -1169,16 +1019,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: @@ -1363,10 +1204,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 @@ -1514,18 +1355,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 @@ -1539,12 +1378,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 @@ -1614,13 +1451,6 @@ __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.2 resolution: "consola@npm:3.4.2" @@ -1628,7 +1458,7 @@ __metadata: 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: @@ -1728,12 +1558,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 @@ -1799,13 +1627,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" @@ -2016,6 +1837,13 @@ __metadata: languageName: node linkType: hard +"es-module-lexer@npm:^1.6.0": + version: 1.6.0 + resolution: "es-module-lexer@npm:1.6.0" + checksum: 10/807ee7020cc46a9c970c78cad1f2f3fc139877e5ebad7f66dbfbb124d451189ba1c48c1c632bd5f8ce1b8af2caef3fca340ba044a410fa890d17b080a59024bb + 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" @@ -2057,86 +1885,6 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.21.3": - version: 0.21.5 - resolution: "esbuild@npm:0.21.5" - dependencies: - "@esbuild/aix-ppc64": "npm:0.21.5" - "@esbuild/android-arm": "npm:0.21.5" - "@esbuild/android-arm64": "npm:0.21.5" - "@esbuild/android-x64": "npm:0.21.5" - "@esbuild/darwin-arm64": "npm:0.21.5" - "@esbuild/darwin-x64": "npm:0.21.5" - "@esbuild/freebsd-arm64": "npm:0.21.5" - "@esbuild/freebsd-x64": "npm:0.21.5" - "@esbuild/linux-arm": "npm:0.21.5" - "@esbuild/linux-arm64": "npm:0.21.5" - "@esbuild/linux-ia32": "npm:0.21.5" - "@esbuild/linux-loong64": "npm:0.21.5" - "@esbuild/linux-mips64el": "npm:0.21.5" - "@esbuild/linux-ppc64": "npm:0.21.5" - "@esbuild/linux-riscv64": "npm:0.21.5" - "@esbuild/linux-s390x": "npm:0.21.5" - "@esbuild/linux-x64": "npm:0.21.5" - "@esbuild/netbsd-x64": "npm:0.21.5" - "@esbuild/openbsd-x64": "npm:0.21.5" - "@esbuild/sunos-x64": "npm:0.21.5" - "@esbuild/win32-arm64": "npm:0.21.5" - "@esbuild/win32-ia32": "npm:0.21.5" - "@esbuild/win32-x64": "npm:0.21.5" - dependenciesMeta: - "@esbuild/aix-ppc64": - optional: true - "@esbuild/android-arm": - optional: true - "@esbuild/android-arm64": - optional: true - "@esbuild/android-x64": - optional: true - "@esbuild/darwin-arm64": - optional: true - "@esbuild/darwin-x64": - optional: true - "@esbuild/freebsd-arm64": - optional: true - "@esbuild/freebsd-x64": - optional: true - "@esbuild/linux-arm": - optional: true - "@esbuild/linux-arm64": - optional: true - "@esbuild/linux-ia32": - optional: true - "@esbuild/linux-loong64": - optional: true - "@esbuild/linux-mips64el": - optional: true - "@esbuild/linux-ppc64": - optional: true - "@esbuild/linux-riscv64": - optional: true - "@esbuild/linux-s390x": - optional: true - "@esbuild/linux-x64": - optional: true - "@esbuild/netbsd-x64": - optional: true - "@esbuild/openbsd-x64": - optional: true - "@esbuild/sunos-x64": - optional: true - "@esbuild/win32-arm64": - optional: true - "@esbuild/win32-ia32": - optional: true - "@esbuild/win32-x64": - optional: true - bin: - esbuild: bin/esbuild - checksum: 10/d2ff2ca84d30cce8e871517374d6c2290835380dc7cd413b2d49189ed170d45e407be14de2cb4794cf76f75cf89955c4714726ebd3de7444b3046f5cab23ab6b - languageName: node - linkType: hard - "esbuild@npm:^0.25.0": version: 0.25.2 resolution: "esbuild@npm:0.25.2" @@ -2391,23 +2139,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" @@ -2415,6 +2146,13 @@ __metadata: languageName: node linkType: hard +"expect-type@npm:^1.2.0": + 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" @@ -2624,13 +2362,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" @@ -2659,13 +2390,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" @@ -2872,13 +2596,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" @@ -3164,13 +2881,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" @@ -3289,13 +2999,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" @@ -3440,16 +3143,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" @@ -3498,12 +3191,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 @@ -3523,7 +3214,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: @@ -3572,13 +3263,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" @@ -3619,13 +3303,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" @@ -3738,18 +3415,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" @@ -3829,15 +3494,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" @@ -3928,15 +3584,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" @@ -3971,15 +3618,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" @@ -4042,13 +3680,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" @@ -4073,24 +3704,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 @@ -4122,17 +3746,6 @@ __metadata: 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 - languageName: node - linkType: hard - "possible-typed-array-names@npm:^1.0.0": version: 1.1.0 resolution: "possible-typed-array-names@npm:1.1.0" @@ -4163,7 +3776,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: @@ -4201,17 +3814,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" @@ -4296,13 +3898,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" @@ -4477,7 +4072,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.1" languageName: unknown linkType: soft @@ -4572,7 +4167,7 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.20.0, rollup@npm:^4.34.8": +"rollup@npm:^4.30.1, rollup@npm:^4.34.8": version: 4.39.0 resolution: "rollup@npm:4.39.0" dependencies: @@ -4875,7 +4470,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 @@ -4965,7 +4560,7 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.5.0": +"std-env@npm:^3.8.1": version: 3.8.1 resolution: "std-env@npm:3.8.1" checksum: 10/ee119570e2e449be86aa4972f119f9086a918307cc524f6e891b7a7c1327a5c970cf1b7d5898c881777845292a7e3380cf7d80ad34aee355d2c22ac5eb628542 @@ -5100,13 +4695,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" @@ -5114,15 +4702,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" @@ -5212,7 +4791,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 @@ -5236,17 +4815,24 @@ __metadata: 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 @@ -5371,13 +4957,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" @@ -5458,13 +5037,6 @@ __metadata: languageName: node linkType: hard -"ufo@npm:^1.5.4": - version: 1.5.4 - resolution: "ufo@npm:1.5.4" - checksum: 10/a885ed421e656aea6ca64e9727b8118a9488715460b6f1a0f0427118adfe2f2830fe7c1d5bd9c5c754a332e6807516551cd663ea67ce9ed6a4e3edc739916335 - languageName: node - linkType: hard - "unbox-primitive@npm:^1.1.0": version: 1.1.0 resolution: "unbox-primitive@npm:1.1.0" @@ -5544,44 +5116,49 @@ __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.1": + version: 3.1.1 + resolution: "vite-node@npm:3.1.1" 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/8243cbc2d83f7862d7882c982e85f3e45a654908de380591edd419338c4c75a7991bd22d12b290ad892b9ea102419e81fde92c87296ec7554f89d2ff2034d5e3 languageName: node linkType: hard -"vite@npm:^5.0.0": - version: 5.4.16 - resolution: "vite@npm:5.4.16" +"vite@npm:^5.0.0 || ^6.0.0": + version: 6.2.4 + resolution: "vite@npm:6.2.4" dependencies: - esbuild: "npm:^0.21.3" + esbuild: "npm:^0.25.0" fsevents: "npm:~2.3.3" - postcss: "npm:^8.4.43" - rollup: "npm:^4.20.0" + postcss: "npm:^8.5.3" + rollup: "npm:^4.30.1" 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: @@ -5596,46 +5173,53 @@ __metadata: optional: true terser: optional: true + tsx: + optional: true + yaml: + optional: true bin: vite: bin/vite.js - checksum: 10/c5010e3962b0a33d50b25296ae9c2f5a45b4b46977b67b9a4016918d932817bb8e46fa14b88d75f752641d4a89f1545966139b58b07dc2d6e3196250a0b239cd + checksum: 10/3734c8695b4d35a5b3ea617159594835e370b428745f37e90d9c1daf82b53af5248578c1f1d9977fc1460320c0cdd4aef135095d378b2eba2736c03e2cfa019e 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.1": + version: 3.1.1 + resolution: "vitest@npm:3.1.1" + dependencies: + "@vitest/expect": "npm:3.1.1" + "@vitest/mocker": "npm:3.1.1" + "@vitest/pretty-format": "npm:^3.1.1" + "@vitest/runner": "npm:3.1.1" + "@vitest/snapshot": "npm:3.1.1" + "@vitest/spy": "npm:3.1.1" + "@vitest/utils": "npm:3.1.1" + chai: "npm:^5.2.0" + debug: "npm:^4.4.0" + expect-type: "npm:^1.2.0" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + std-env: "npm:^3.8.1" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^0.3.2" + tinypool: "npm:^1.0.2" + tinyrainbow: "npm:^2.0.0" + vite: "npm:^5.0.0 || ^6.0.0" + vite-node: "npm:3.1.1" + 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.1 + "@vitest/ui": 3.1.1 happy-dom: "*" jsdom: "*" peerDependenciesMeta: "@edge-runtime/vm": optional: true + "@types/debug": + optional: true "@types/node": optional: true "@vitest/browser": @@ -5648,7 +5232,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 10/50d551be2cf6621d3844c42924595007befd73e10e9406e0fa08f1239e2c012d08f85b0a70d8656a11364a6a58930600c35a5ee00d8445071f0ab0afcacd085a + checksum: 10/9dc54ef6854f877ad524667a0f3798b6c97c8138bee15a3dbad76557a45e3a3e42d438140df7a9eeaa10e5da7b5eb74ba854f06ffd233fa3c9e5936f6ae42e97 languageName: node linkType: hard @@ -5795,7 +5379,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: @@ -5921,10 +5505,3 @@ __metadata: checksum: 10/f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard - -"yocto-queue@npm:^1.0.0": - version: 1.2.1 - resolution: "yocto-queue@npm:1.2.1" - checksum: 10/0843d6c2c0558e5c06e98edf9c17942f25c769e21b519303a5c2adefd5b738c9b2054204dc856ac0cd9d134b1bc27d928ce84fd23c9e2423b7e013d5a6f50577 - languageName: node - linkType: hard From be7877c1f9618afe0d32997a95c0d5196e8619cd Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Fri, 28 Feb 2025 13:46:00 -0600 Subject: [PATCH 59/60] Migrate remaining type tests to `vitest` --- type-tests/argsMemoize.test-d.ts | 8 ++++---- type-tests/createSelector.test-d.ts | 4 ++-- type-tests/createSelectorCreator.test-d.ts | 4 ++-- type-tests/createStructuredSelector.test-d.ts | 2 +- type-tests/createStructuredSelector.withTypes.test-d.ts | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/type-tests/argsMemoize.test-d.ts b/type-tests/argsMemoize.test-d.ts index 378a990bd..0e8412089 100644 --- a/type-tests/argsMemoize.test-d.ts +++ b/type-tests/argsMemoize.test-d.ts @@ -992,19 +992,19 @@ describe('type tests', () => { }[] >() - expectTypeOf(selectorDefaultParametric).parameters.not.toMatchTypeOf< + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< [RootState] >() - expectTypeOf(selectorDefaultParametric).parameters.not.toMatchTypeOf< + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< [number] >() - expectTypeOf(selectorDefaultParametric).parameters.not.toMatchTypeOf< + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< [RootState, string] >() - expectTypeOf(selectorDefaultParametric).parameters.not.toMatchTypeOf< + expectTypeOf(selectorDefaultParametric).parameters.not.toMatchObjectType< [RootState, number, number] >() diff --git a/type-tests/createSelector.test-d.ts b/type-tests/createSelector.test-d.ts index ea8ceb15a..a66b1fa17 100644 --- a/type-tests/createSelector.test-d.ts +++ b/type-tests/createSelector.test-d.ts @@ -73,7 +73,7 @@ describe('type tests', () => { const selector = createSelector((state: State) => state.bar, subSelector) - expectTypeOf(selector).parameter(0).not.toMatchTypeOf({ foo: '' }) + expectTypeOf(selector).parameter(0).not.toMatchObjectType<{ foo: '' }>() expectTypeOf(selector({ bar: { foo: '' } })).not.toBeNumber() @@ -112,7 +112,7 @@ describe('type tests', () => { expectTypeOf(connected) .parameter(0) - .not.toMatchTypeOf({ bar: 42, baz: 123 }) + .not.toMatchObjectType<{ bar: 42; baz: 123 }>() }) test('invalid type in combiner', () => { diff --git a/type-tests/createSelectorCreator.test-d.ts b/type-tests/createSelectorCreator.test-d.ts index 2ee0f6d3e..ff09807c2 100644 --- a/type-tests/createSelectorCreator.test-d.ts +++ b/type-tests/createSelectorCreator.test-d.ts @@ -3,9 +3,9 @@ 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' @@ -73,7 +73,7 @@ describe('type tests', () => { expectTypeOf(selector({ foo: 'fizz' })).toBeString() - expectTypeOf(selector).parameter(1).not.toMatchTypeOf({ bar: 42 }) + expectTypeOf(selector).parameter(1).not.toMatchObjectType<{ bar: 42 }>() // clearCache should exist because of lruMemoize expectTypeOf(selector.clearCache).toBeFunction() diff --git a/type-tests/createStructuredSelector.test-d.ts b/type-tests/createStructuredSelector.test-d.ts index e6a665340..201c5548f 100644 --- a/type-tests/createStructuredSelector.test-d.ts +++ b/type-tests/createStructuredSelector.test-d.ts @@ -194,7 +194,7 @@ describe('type tests', () => { expectTypeOf(structuredSelector.clearCache).parameters.toEqualTypeOf<[]>() - expectTypeOf(structuredSelector.dependencies).items.toMatchTypeOf< + expectTypeOf(structuredSelector.dependencies).items.toExtend< Selector >() diff --git a/type-tests/createStructuredSelector.withTypes.test-d.ts b/type-tests/createStructuredSelector.withTypes.test-d.ts index 98d3aba71..a3af33e2b 100644 --- a/type-tests/createStructuredSelector.withTypes.test-d.ts +++ b/type-tests/createStructuredSelector.withTypes.test-d.ts @@ -218,7 +218,7 @@ describe('type tests', () => { [] >() - expectTypeOf(structuredAppSelector.dependencies).items.toMatchTypeOf< + expectTypeOf(structuredAppSelector.dependencies).items.toExtend< Selector >() From 5cad3ef71ddb086e4d52c27c88f613b8267546dc Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Sat, 24 Feb 2024 03:57:16 -0600 Subject: [PATCH 60/60] Add `@types/node` to `devDependencies` --- package.json | 1 + yarn.lock | 43 ++++++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 08407cf43..2b8b48730 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@reduxjs/toolkit": "^2.0.1", "@testing-library/react": "^14.1.2", "@types/lodash": "^4.14.175", + "@types/node": "^22.14.0", "@types/react": "^18.2.38", "@types/react-dom": "^18.2.17", "@types/shelljs": "^0.8.11", diff --git a/yarn.lock b/yarn.lock index 724c0c80f..8dc3a532b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -700,7 +700,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*": +"@types/node@npm:*, @types/node@npm:^22.14.0": version: 22.14.0 resolution: "@types/node@npm:22.14.0" dependencies: @@ -1004,9 +1004,9 @@ __metadata: 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 @@ -1986,8 +1986,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" @@ -1999,7 +1999,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" @@ -2009,7 +2009,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 @@ -3539,7 +3539,7 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.8": +"object.entries@npm:^1.1.9": version: 1.1.9 resolution: "object.entries@npm:1.1.9" dependencies: @@ -4048,6 +4048,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.14.0" "@types/react": "npm:^18.2.38" "@types/react-dom": "npm:^18.2.17" "@types/shelljs": "npm:^0.8.11" @@ -4561,9 +4562,9 @@ __metadata: linkType: hard "std-env@npm:^3.8.1": - version: 3.8.1 - resolution: "std-env@npm:3.8.1" - checksum: 10/ee119570e2e449be86aa4972f119f9086a918307cc524f6e891b7a7c1327a5c970cf1b7d5898c881777845292a7e3380cf7d80ad34aee355d2c22ac5eb628542 + version: 3.9.0 + resolution: "std-env@npm:3.9.0" + checksum: 10/3044b2c54a74be4f460db56725571241ab3ac89a91f39c7709519bc90fa37148784bc4cd7d3a301aa735f43bd174496f263563f76703ce3e81370466ab7c235b languageName: node linkType: hard @@ -5018,22 +5019,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 + checksum: 10/98470634034ec37fd9ea61cc82dcf9a27950d0117a4646146b767d085a2ec14b137aae9642a83d1c62732d7fdcdac19bb6288b0bb468a72f7a06ae4e1d2c72c9 languageName: node linkType: hard @@ -5132,8 +5133,8 @@ __metadata: linkType: hard "vite@npm:^5.0.0 || ^6.0.0": - version: 6.2.4 - resolution: "vite@npm:6.2.4" + version: 6.2.6 + resolution: "vite@npm:6.2.6" dependencies: esbuild: "npm:^0.25.0" fsevents: "npm:~2.3.3" @@ -5179,7 +5180,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10/3734c8695b4d35a5b3ea617159594835e370b428745f37e90d9c1daf82b53af5248578c1f1d9977fc1460320c0cdd4aef135095d378b2eba2736c03e2cfa019e + checksum: 10/d8fb01a190e31fcf2189e028aed444d68255b5397d5e2c52fa73f8a0de0b052b06fbbe3793c88e7992f4297832336a23cf8bec14c88b9c2ef8aa0bce98219e50 languageName: node linkType: hard