diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 5a71532bbb..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,61 +0,0 @@ -module.exports = { - extends: ['react-app', 'prettier'], - parser: '@typescript-eslint/parser', - rules: { - 'jsx-a11y/href-no-hash': 'off', - 'react/react-in-jsx-scope': 'off', - // Taken care of by TypeScript's `noUnusedLocals` / `noUnusedParameters` - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': 'off', - // Silence some bizarre "rule not found" TSLint error - '@typescript-eslint/no-angle-bracket-type-assertion': 'off', - 'no-redeclare': 'off', - // Silence some bizarre "rule not found" TSLint error - '@typescript-eslint/no-redeclare': 'off', - 'no-use-before-define': 'off', - '@typescript-eslint/no-use-before-define': ['error', { functions: false }], - '@typescript-eslint/consistent-type-imports': [ - 'error', - { prefer: 'type-imports', disallowTypeAnnotations: false }, - ], - 'react-hooks/exhaustive-deps': [ - 'warn', - { - additionalHooks: '(usePossiblyImmediateEffect)', - }, - ], - }, - overrides: [ - // { - // // only add after https://github.com/typescript-eslint/typescript-eslint/pull/3463 is merged - // files: ['src/**/*.ts'], - // excludedFiles: [ - // '**/tests/*.ts', - // '**/tests/**/*.ts', - // '**/tests/*.tsx', - // '**/tests/**/*.tsx', - // ], - // parserOptions: { - // project: './tsconfig.json', - // }, - // rules: { - // '@typescript-eslint/prefer-readonly-parameter-types': [ - // 'warn', - // { arraysAndTuplesOnly: true }, - // ], - // }, - // }, - { - files: [ - 'packages/toolkit/src/tests/*.ts', - 'packages/toolkit/src/**/tests/*.ts', - 'packages/toolkit/src/**/tests/*.tsx', - ], - rules: { - '@typescript-eslint/no-unused-expressions': 'off', - 'no-lone-blocks': 'off', - 'no-sequences': 'off', - }, - }, - ], -} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 703b68cb09..3ed8da42b7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,6 +14,10 @@ on: - '@rtk-query/codegen-openapi' - '@rtk-query/graphql-request-base-query' - '@reduxjs/rtk-codemods' + - '@reduxjs/eslint-config' + - '@reduxjs/prettier-config' + - '@reduxjs/tsconfig' + - '@reduxjs/vitest-config' jobs: publish: runs-on: ubuntu-latest @@ -28,7 +32,7 @@ jobs: registry-url: 'https://registry.npmjs.org' cache: 'yarn' - run: yarn install --frozen-lockfile - - run: yarn workspace ${{ inputs.package }} test + - run: yarn workspaces foreach --include "${{ inputs.package }}" run test - run: yarn workspace ${{ inputs.package }} exec npm publish --access public --provenance env: NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml new file mode 100644 index 0000000000..baa9908dac --- /dev/null +++ b/.github/workflows/test-configs.yml @@ -0,0 +1,117 @@ +name: Test Configs + +on: [push, pull_request, workflow_dispatch] + +jobs: + test-types: + name: Test types with TypeScript ${{ matrix.ts }} on ${{ matrix.os }} and Node.js ${{ matrix.node }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + + matrix: + package: + [ + '@reduxjs/eslint-config', + '@reduxjs/prettier-config', + '@reduxjs/vitest-config', + ] + node: ['22.x'] + os: [ubuntu-latest] + ts: ['5.3', '5.4', '5.5', '5.6', '5.7', '5.8'] + + steps: + - name: Checkout repository + 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: Install TypeScript ${{ matrix.ts }} + run: yarn up typescript@${{ matrix.ts }} + + - name: Run type tests + run: yarn workspace ${{ matrix.package }} run test-types + + are-the-types-wrong: + name: Check if the type definitions for ${{ matrix.package }} are correct with Node.js ${{ matrix.node }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + + matrix: + node: ['22.x'] + package: + [ + '@reduxjs/eslint-config', + '@reduxjs/prettier-config', + '@reduxjs/tsconfig', + '@reduxjs/vitest-config', + ] + os: [ubuntu-latest] + + steps: + - name: Checkout repository + 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: Run are-the-types-wrong for ${{ matrix.package }} with Node.js ${{ matrix.node }} on ${{ matrix.os }} + run: yarn workspace ${{ matrix.package }} run check-exports --format table + + - name: Did we fail? + if: failure() + run: ls -R + + publint: + name: Check if the package.json for ${{ matrix.package }} is correct with Node.js ${{ matrix.node }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + + matrix: + node: ['22.x'] + package: + [ + '@reduxjs/eslint-config', + '@reduxjs/prettier-config', + '@reduxjs/tsconfig', + '@reduxjs/vitest-config', + ] + os: [ubuntu-latest] + + steps: + - name: Checkout repository + 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: Run publint for ${{ matrix.package }} with Node.js ${{ matrix.node }} on ${{ matrix.os }} + run: yarn workspace ${{ matrix.package }} run check-package-json + + - name: Did we fail? + if: failure() + run: ls -R diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8558ad9a43..59d51d9f59 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,6 +46,12 @@ jobs: - name: Install deps run: yarn install + - name: Check formatting + run: yarn workspaces foreach -Ap -j unlimited run format-check + + - name: Lint files + run: yarn workspaces foreach -Ap -j unlimited run lint + # Read existing version, reuse that, add a Git short hash - name: Set build version to Git commit run: yarn tsx scripts/writeGitVersion.mts $(git rev-parse --short HEAD) diff --git a/.gitignore b/.gitignore index 78e8787e73..ec63be8a36 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ tsconfig.vitest-temp.json # node version manager files .node-version -.nvmrc \ No newline at end of file +.nvmrc + +.eslintcache diff --git a/.prettierignore b/.prettierignore index 46179d7498..d2ba6ec0a6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,5 @@ -**/dist/** -**/etc/** -**/temp/** -**/__testfixtures__/** \ No newline at end of file +__testfixtures__/ +.docusaurus/ +.next/ +examples/publish-ci/ +.yarn/ diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index b2095be81e..0000000000 --- a/.prettierrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "semi": false, - "singleQuote": true -} diff --git a/docs/api/actionCreatorMiddleware.mdx b/docs/api/actionCreatorMiddleware.mdx index fede5df8c3..16281ade91 100644 --- a/docs/api/actionCreatorMiddleware.mdx +++ b/docs/api/actionCreatorMiddleware.mdx @@ -54,7 +54,7 @@ import reducer from './reducer' // Augment middleware to consider all functions with a static type property to be action creators const isActionCreator = ( action: unknown, -): action is Function & { type: unknown } => +): action is (...args: any) => any & { type: unknown } => typeof action === 'function' && 'type' in action const actionCreatorMiddleware = createActionCreatorInvariantMiddleware({ diff --git a/docs/api/createListenerMiddleware.mdx b/docs/api/createListenerMiddleware.mdx index a805e2ebe9..51084b831f 100644 --- a/docs/api/createListenerMiddleware.mdx +++ b/docs/api/createListenerMiddleware.mdx @@ -488,7 +488,7 @@ To fix this, the middleware provides types for defining "pre-typed" versions of import { createListenerMiddleware, addListener } from '@reduxjs/toolkit' import type { RootState, AppDispatch } from './store' -declare type ExtraArgument = {foo: string}; +declare type ExtraArgument = { foo: string } export const listenerMiddleware = createListenerMiddleware() diff --git a/docs/package.json b/docs/package.json index 72b17dc4e2..9f0a100259 100644 --- a/docs/package.json +++ b/docs/package.json @@ -2,6 +2,7 @@ "name": "docs", "devDependencies": { "@manaflair/redux-batch": "^1.0.0", + "@reduxjs/tsconfig": "workspace:^", "@types/nanoid": "^2.1.0", "@types/react": "^19.0.1", "async-mutex": "^0.3.2", @@ -12,6 +13,7 @@ "nanoid": "^3.1.23", "next-redux-wrapper": "^7.0.5", "redux-persist": "^6.0.0", - "rxjs": "^6.6.2" + "rxjs": "^6.6.2", + "typescript": "^5.9.3" } } diff --git a/docs/rtk-query/api/created-api/hooks.mdx b/docs/rtk-query/api/created-api/hooks.mdx index 333f91ee7e..803705b64e 100644 --- a/docs/rtk-query/api/created-api/hooks.mdx +++ b/docs/rtk-query/api/created-api/hooks.mdx @@ -419,7 +419,6 @@ selectFromResult: () => ({}) ::: - **Parameters** - - `options`: A set of options that control the subscription behavior of the hook: - `selectFromResult`: A callback that can be used to customize the mutation result returned as the second item in the tuple - `fixedCacheKey`: An optional string used to enable shared results across hook instances @@ -622,7 +621,6 @@ type UseLazyQueryLastPromiseInfo = { ``` - **Parameters** - - `options`: A set of options that control the fetching behavior and returned result value of the hook. Options affecting fetching behavior will only have an effect after the lazy query has been triggered at least once. - **Returns**: A tuple containing: @@ -666,7 +664,6 @@ type PrefetchCallback = (arg: any, options?: UsePrefetchOptions) => void ``` - **Parameters** - - `endpointName`: The name of the endpoint to prefetch data for - `options`: A set of options that control whether the prefetch request should occur @@ -734,7 +731,6 @@ type UseQueryStateResult = { ``` - **Parameters** - - `arg`: The argument passed to the query defined in the endpoint. You can also pass in `skipToken` here as an alternative way of skipping the selection, see [skipToken](#skiptoken) - `options`: A set of options that control the return value for the hook @@ -773,7 +769,6 @@ type UseQuerySubscriptionResult = { ``` - **Parameters** - - `arg`: The argument passed to the query defined in the endpoint. You can also pass in `skipToken` here as an alternative way of skipping the query, see [skipToken](#skiptoken) - `options`: A set of options that control the fetching behavior of the hook @@ -829,7 +824,6 @@ type UseLazyQuerySubscriptionTrigger = ( ``` - **Parameters** - - `options`: A set of options that control the fetching behavior of the hook. The options will only have an effect after the lazy query has been triggered at least once. - **Returns**: A tuple containing: diff --git a/docs/rtk-query/comparison.md b/docs/rtk-query/comparison.md index 4cb4127fcf..261f4b6cf7 100644 --- a/docs/rtk-query/comparison.md +++ b/docs/rtk-query/comparison.md @@ -75,8 +75,8 @@ This comparison table strives to be as accurate and as unbiased as possible. If | **API Definition** | declarative | on use, declarative | GraphQL schema | GraphQL schema | | **Cache by** | endpoint + serialized arguments | user-defined query-key | type/id | type/id? | | **Invalidation Strategy + Refetching** | declarative, by type and/or type/id | manual by cache key | automatic cache updates on per-entity level, manual query invalidation by cache key | declarative, by type OR automatic cache updates on per-entity level, manual query invalidation by cache key | -| **Polling** | yes | yes | yes | yes | -| **Parallel queries** | yes | yes | yes | yes | +| **Polling** | yes | yes | yes | yes | +| **Parallel queries** | yes | yes | yes | yes | | **Dependent queries** | yes | yes | yes | yes | | **Skip queries** | yes | yes | yes | yes | | **Lagged queries** | yes | yes | no | ? | diff --git a/docs/rtk-query/usage/queries.mdx b/docs/rtk-query/usage/queries.mdx index 205c1fe0a0..e67cc78765 100644 --- a/docs/rtk-query/usage/queries.mdx +++ b/docs/rtk-query/usage/queries.mdx @@ -287,7 +287,9 @@ function PostsList() { return ( ) } diff --git a/docs/tsconfig.json b/docs/tsconfig.json index 5692743ab2..05b4334a35 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -1,4 +1,5 @@ { + "extends": "@reduxjs/tsconfig/base", "compilerOptions": { "allowSyntheticDefaultImports": true, "esModuleInterop": true, diff --git a/docs/virtual/matchers/index.ts b/docs/virtual/matchers/index.ts index aba086bcf5..8f2453871c 100644 --- a/docs/virtual/matchers/index.ts +++ b/docs/virtual/matchers/index.ts @@ -1,8 +1,5 @@ -import { - createAsyncThunk, - createReducer, - PayloadAction, -} from '@reduxjs/toolkit' +import type { PayloadAction } from '@reduxjs/toolkit' +import { createAsyncThunk, createReducer } from '@reduxjs/toolkit' export interface Data { isInteresting: boolean diff --git a/docs/virtual/petstore-api.generated/petstore-api.generated.ts b/docs/virtual/petstore-api.generated/petstore-api.generated.ts index c885323c48..1bba1ce78b 100644 --- a/docs/virtual/petstore-api.generated/petstore-api.generated.ts +++ b/docs/virtual/petstore-api.generated/petstore-api.generated.ts @@ -123,6 +123,7 @@ export const api = createApi({ }), }), }) +type AnyNonNullishValue = NonNullable export type UpdatePetApiResponse = /** status 200 Successful operation */ Pet export type UpdatePetApiArg = { /** Update an existent pet in the store */ @@ -174,10 +175,9 @@ export type UploadFileApiArg = { additionalMetadata?: string body: string } -export type GetInventoryApiResponse = /** status 200 successful operation */ { - [key: string]: number -} -export type GetInventoryApiArg = {} +export type GetInventoryApiResponse = + /** status 200 successful operation */ Record +export type GetInventoryApiArg = AnyNonNullishValue export type PlaceOrderApiResponse = /** status 200 successful operation */ Order export type PlaceOrderApiArg = { order: Order @@ -211,7 +211,7 @@ export type LoginUserApiArg = { password?: string } export type LogoutUserApiResponse = unknown -export type LogoutUserApiArg = {} +export type LogoutUserApiArg = AnyNonNullishValue export type GetUserByNameApiResponse = /** status 200 successful operation */ User export type GetUserByNameApiArg = { diff --git a/errors.json b/errors.json index 984b6dd650..7331a50e90 100644 --- a/errors.json +++ b/errors.json @@ -43,4 +43,4 @@ "41": "getPreviousPageParam for endpoint '' must be a function if maxPages is used", "42": "Duplicate middleware references found when creating the store. Ensure that each middleware is only included once.", "43": "`builder.addAsyncThunk` should only be called before calling `builder.addDefaultCase`" -} \ No newline at end of file +} diff --git a/eslint.config.mts b/eslint.config.mts new file mode 100644 index 0000000000..beec2538cd --- /dev/null +++ b/eslint.config.mts @@ -0,0 +1,104 @@ +import { createESLintConfig } from '@reduxjs/eslint-config' +import eslintConfigPackageJson from '@reduxjs/eslint-config/package.json' with { type: 'json' } + +const basename = `${eslintConfigPackageJson.name}/overrides` + +const eslintConfig = createESLintConfig([ + { + name: `${basename}/global-ignores`, + ignores: [ + 'packages/rtk-codemods/transforms/*/__testfixtures__/', + 'packages/toolkit/.size-limit.cjs', + 'packages/rtk-query-codegen-openapi/lib/', + 'packages/rtk-query-codegen-openapi/test/config.example.js', + 'examples/publish-ci/', + + // TODO: Remove this later. + 'examples/', + ], + }, + + { + name: `${basename}/main`, + files: ['**/*.?(c|m)[jt]s?(x)'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + // TODO: Enable this later. + '@typescript-eslint/consistent-type-definitions': [0, 'type'], + '@typescript-eslint/prefer-nullish-coalescing': [0], + '@typescript-eslint/no-namespace': [0], + '@typescript-eslint/require-await': [0], + '@typescript-eslint/unified-signatures': [0], + '@typescript-eslint/no-unnecessary-type-parameters': [0], + '@typescript-eslint/no-invalid-void-type': [0], + '@typescript-eslint/no-unnecessary-type-arguments': [0], + '@typescript-eslint/no-confusing-void-expression': [0], + '@typescript-eslint/no-duplicate-type-constituents': [0], + '@typescript-eslint/no-redundant-type-constituents': [0], + '@typescript-eslint/no-unnecessary-type-assertion': [0], + 'object-shorthand': [0], + '@typescript-eslint/no-explicit-any': [ + 0, + { + fixToUnknown: false, + ignoreRestArgs: false, + }, + ], + }, + }, + + { + name: `${basename}/vitest-custom-matchers-declaration-file`, + files: ['packages/toolkit/src/tests/utils/CustomMatchers.d.ts'], + rules: { + '@typescript-eslint/no-empty-object-type': [ + 2, + { + allowInterfaces: 'with-single-extends', + allowObjectTypes: 'never', + }, + ], + }, + }, + + { + name: `${basename}/no-require-imports`, + files: ['examples/query/react/graphql-codegen/src/mocks/schema.js'], + languageOptions: { + sourceType: 'commonjs', + }, + rules: { + '@typescript-eslint/no-require-imports': [ + 2, + { + allow: ['ts-node', '\\./db(.c?[tj]s)?$'], + allowAsImport: false, + }, + ], + }, + }, + + { + name: `${basename}/examples/type-portability/nodenext-cjs`, + files: ['examples/type-portability/nodenext-cjs/**/*.?(c)ts?(x)'], + languageOptions: { + sourceType: 'commonjs', + }, + rules: { + '@typescript-eslint/no-namespace': [ + 0, + { + allowDeclarations: false, + allowDefinitionFiles: true, + }, + ], + }, + }, +]) + +export default eslintConfig diff --git a/examples/action-listener/counter/package.json b/examples/action-listener/counter/package.json index 925ec93bd9..f8f5400f8a 100644 --- a/examples/action-listener/counter/package.json +++ b/examples/action-listener/counter/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@reduxjs/toolkit": "^1.8.0", - "@types/node": "^12.0.0", + "@types/node": "^24.9.1", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", "clsx": "1.1.1", @@ -12,7 +12,7 @@ "react-dom": "^19.0.0", "react-redux": "^9.1.2", "react-scripts": "5.0.1", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "scripts": { "start": "react-scripts start", @@ -41,6 +41,7 @@ ] }, "devDependencies": { + "@reduxjs/tsconfig": "workspace:^", "jest-watch-typeahead": "^1.1.0" } } diff --git a/examples/action-listener/counter/src/components/App/App.tsx b/examples/action-listener/counter/src/components/App/App.tsx index ca09482b2b..52778a0525 100644 --- a/examples/action-listener/counter/src/components/App/App.tsx +++ b/examples/action-listener/counter/src/components/App/App.tsx @@ -1,12 +1,12 @@ +import type { Unsubscribe } from '@reduxjs/toolkit' import React, { useEffect } from 'react' import { Provider } from 'react-redux' -import type { Unsubscribe } from '@reduxjs/toolkit' -import { setupThemeListeners } from '../../services/theme/listeners' import { setupCounterListeners } from '../../services/counter/listeners' +import { setupThemeListeners } from '../../services/theme/listeners' +import { startAppListening, store } from '../../store' import { ChangeThemeForm } from '../ChangeThemeForm/ChangeThemeForm' import { CounterList } from '../CounterList/CounterList' import { CreateCounterForm } from '../CreateCounterForm/CreateCounterForm' -import { store, startAppListening } from '../../store' export function App() { useEffect(() => { diff --git a/examples/action-listener/counter/src/components/ChangeThemeForm/ChangeThemeForm.tsx b/examples/action-listener/counter/src/components/ChangeThemeForm/ChangeThemeForm.tsx index 5916c338d5..9d05de219d 100644 --- a/examples/action-listener/counter/src/components/ChangeThemeForm/ChangeThemeForm.tsx +++ b/examples/action-listener/counter/src/components/ChangeThemeForm/ChangeThemeForm.tsx @@ -1,6 +1,7 @@ -import { FormEvent, ChangeEvent } from 'react' +import type { ChangeEvent, FormEvent } from 'react' +import type { ThemeState } from '../../services/theme/slice' +import { themeActions } from '../../services/theme/slice' import { useAppDispatch, useAppSelector } from '../../store' -import { themeActions, ThemeState } from '../../services/theme/slice' import styles from './changeThemeForm.module.css' function isChecked(theme: ThemeState): boolean { diff --git a/examples/action-listener/counter/src/components/Counter/Counter.tsx b/examples/action-listener/counter/src/components/Counter/Counter.tsx index 92a878c0c5..0f18df3074 100644 --- a/examples/action-listener/counter/src/components/Counter/Counter.tsx +++ b/examples/action-listener/counter/src/components/Counter/Counter.tsx @@ -1,9 +1,9 @@ -import { EntityId } from '@reduxjs/toolkit' +import type { EntityId } from '@reduxjs/toolkit' +import clsx from 'clsx' import { memo } from 'react' import { counterActions, counterSelectors } from '../../services/counter/slice' import { useAppDispatch, useAppSelector } from '../../store' import styles from './counter.module.css' -import clsx from 'clsx' export interface CounterProps { counterId: EntityId diff --git a/examples/action-listener/counter/src/components/CreateCounterForm/CreateCounterForm.tsx b/examples/action-listener/counter/src/components/CreateCounterForm/CreateCounterForm.tsx index 250afcf188..21574db355 100644 --- a/examples/action-listener/counter/src/components/CreateCounterForm/CreateCounterForm.tsx +++ b/examples/action-listener/counter/src/components/CreateCounterForm/CreateCounterForm.tsx @@ -1,8 +1,9 @@ -import { FormEvent, useState } from 'react' -import styles from './createCounter.module.css' import clsx from 'clsx' -import { useAppDispatch } from '../../store' +import type { FormEvent } from 'react' +import { useState } from 'react' import { counterActions } from '../../services/counter/slice' +import { useAppDispatch } from '../../store' +import styles from './createCounter.module.css' const sectionClassname = clsx('paper', styles.section) diff --git a/examples/action-listener/counter/src/index.css b/examples/action-listener/counter/src/index.css index cc09e5d2c9..0b52d120a7 100644 --- a/examples/action-listener/counter/src/index.css +++ b/examples/action-listener/counter/src/index.css @@ -1,15 +1,15 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: + -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: + source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } h1 { diff --git a/examples/action-listener/counter/src/services/counter/listeners.ts b/examples/action-listener/counter/src/services/counter/listeners.ts index 4c2f6db754..8bf96359b1 100644 --- a/examples/action-listener/counter/src/services/counter/listeners.ts +++ b/examples/action-listener/counter/src/services/counter/listeners.ts @@ -1,12 +1,11 @@ -import { counterActions, counterSelectors } from './slice' -import { - UnknownAction, - isAllOf, - isAnyOf, +import type { PayloadAction, + UnknownAction, Unsubscribe, } from '@reduxjs/toolkit' +import { isAllOf, isAnyOf } from '@reduxjs/toolkit' import type { AppListenerEffectAPI, AppStartListening } from '../../store' +import { counterActions, counterSelectors } from './slice' function shouldStopAsyncTasksOf(id: string) { return isAllOf( diff --git a/examples/action-listener/counter/src/services/counter/slice.ts b/examples/action-listener/counter/src/services/counter/slice.ts index fbd8680606..17b6455345 100644 --- a/examples/action-listener/counter/src/services/counter/slice.ts +++ b/examples/action-listener/counter/src/services/counter/slice.ts @@ -1,9 +1,5 @@ -import { - createSlice, - createEntityAdapter, - nanoid, - PayloadAction, -} from '@reduxjs/toolkit' +import type { PayloadAction } from '@reduxjs/toolkit' +import { createEntityAdapter, createSlice, nanoid } from '@reduxjs/toolkit' export interface Counter { value: number @@ -70,7 +66,9 @@ export const counterSlice = createSlice({ updateByAsync( _, action: PayloadAction<{ id: string; delta: number; delayMs: number }>, - ) {}, + ) { + /* No-Op */ + }, cancelAsyncUpdates(state, { payload }: PayloadAction) { delete state.counters.entities[payload]?.intervalMs }, diff --git a/examples/action-listener/counter/src/services/counter/tests/listener.test.ts b/examples/action-listener/counter/src/services/counter/tests/listener.test.ts index c5ef961322..b8858c6a5c 100644 --- a/examples/action-listener/counter/src/services/counter/tests/listener.test.ts +++ b/examples/action-listener/counter/src/services/counter/tests/listener.test.ts @@ -1,7 +1,7 @@ import { configureStore, createListenerMiddleware } from '@reduxjs/toolkit' -import { setupCounterListeners } from '../listeners' -import { counterSlice, counterActions, counterSelectors } from '../slice' import type { AppStartListening } from '../../../store' +import { setupCounterListeners } from '../listeners' +import { counterActions, counterSelectors, counterSlice } from '../slice' function delay(timerMs: number): Promise { return new Promise((resolve) => { @@ -12,7 +12,9 @@ function delay(timerMs: number): Promise { jest.useRealTimers() describe('counter - listeners', () => { - const onMiddlewareError = jest.fn((): void => {}) // https://jestjs.io/docs/mock-function-api + const onMiddlewareError = jest.fn((): void => { + /* No-Op */ + }) // https://jestjs.io/docs/mock-function-api /** * @see https://redux-toolkit.js.org/api/createListenerMiddleware diff --git a/examples/action-listener/counter/src/services/theme/listeners.ts b/examples/action-listener/counter/src/services/theme/listeners.ts index 2cbbdd0b87..7834cdbf17 100644 --- a/examples/action-listener/counter/src/services/theme/listeners.ts +++ b/examples/action-listener/counter/src/services/theme/listeners.ts @@ -1,6 +1,6 @@ -import { themeActions } from './slice' +import type { Unsubscribe } from '@reduxjs/toolkit' import type { AppStartListening } from '../../store' -import { Unsubscribe } from '@reduxjs/toolkit' +import { themeActions } from './slice' function onChangeColorScheme( action: ReturnType, diff --git a/examples/action-listener/counter/src/store.ts b/examples/action-listener/counter/src/store.ts index 8abb0ea3a7..06ae7d9a11 100644 --- a/examples/action-listener/counter/src/store.ts +++ b/examples/action-listener/counter/src/store.ts @@ -1,12 +1,15 @@ -import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' +import type { + ListenerEffectAPI, + TypedAddListener, + TypedStartListening, +} from '@reduxjs/toolkit' import { + addListener, configureStore, createListenerMiddleware, - TypedStartListening, - TypedAddListener, - ListenerEffectAPI, - addListener, } from '@reduxjs/toolkit' +import type { TypedUseSelectorHook } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { counterSlice } from './services/counter/slice' import { themeSlice } from './services/theme/slice' diff --git a/examples/action-listener/counter/tsconfig.json b/examples/action-listener/counter/tsconfig.json index 9d379a3c4a..6812fef180 100644 --- a/examples/action-listener/counter/tsconfig.json +++ b/examples/action-listener/counter/tsconfig.json @@ -1,20 +1,5 @@ { - "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" - }, + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, "include": ["src"] } diff --git a/examples/publish-ci/cra4/src/index.css b/examples/publish-ci/cra4/src/index.css index ec2585e8c0..84640987c3 100644 --- a/examples/publish-ci/cra4/src/index.css +++ b/examples/publish-ci/cra4/src/index.css @@ -1,13 +1,13 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: + -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: + source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } diff --git a/examples/publish-ci/cra5/src/index.css b/examples/publish-ci/cra5/src/index.css index ec2585e8c0..84640987c3 100644 --- a/examples/publish-ci/cra5/src/index.css +++ b/examples/publish-ci/cra5/src/index.css @@ -1,13 +1,13 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: + -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: + source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } diff --git a/examples/publish-ci/vite/src/index.css b/examples/publish-ci/vite/src/index.css index ec2585e8c0..84640987c3 100644 --- a/examples/publish-ci/vite/src/index.css +++ b/examples/publish-ci/vite/src/index.css @@ -1,13 +1,13 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: + -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: + source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } diff --git a/examples/query/react/advanced/package.json b/examples/query/react/advanced/package.json index 79669621be..0b5967470a 100644 --- a/examples/query/react/advanced/package.json +++ b/examples/query/react/advanced/package.json @@ -13,9 +13,10 @@ "react-scripts": "5.0.1" }, "devDependencies": { + "@reduxjs/tsconfig": "workspace:^", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "eslintConfig": { "extends": [ diff --git a/examples/query/react/advanced/tsconfig.json b/examples/query/react/advanced/tsconfig.json index 2e7afa3896..6812fef180 100644 --- a/examples/query/react/advanced/tsconfig.json +++ b/examples/query/react/advanced/tsconfig.json @@ -1,20 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/authentication-with-extrareducers/package.json b/examples/query/react/authentication-with-extrareducers/package.json index bc59220744..b9a5915f2a 100644 --- a/examples/query/react/authentication-with-extrareducers/package.json +++ b/examples/query/react/authentication-with-extrareducers/package.json @@ -20,9 +20,10 @@ "react-scripts": "5.0.1" }, "devDependencies": { + "@reduxjs/tsconfig": "workspace:^", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "scripts": { "start": "react-scripts start", diff --git a/examples/query/react/authentication-with-extrareducers/src/App.tsx b/examples/query/react/authentication-with-extrareducers/src/App.tsx index 9a8fbd70ca..872ed02025 100644 --- a/examples/query/react/authentication-with-extrareducers/src/App.tsx +++ b/examples/query/react/authentication-with-extrareducers/src/App.tsx @@ -1,9 +1,8 @@ -import { Routes, Route } from 'react-router-dom' import { Box, Center, VStack } from '@chakra-ui/react' - +import { Route, Routes } from 'react-router-dom' import { Login } from './features/auth/Login' -import { PrivateOutlet } from './utils/PrivateOutlet' import { ProtectedComponent } from './features/auth/ProtectedComponent' +import { PrivateOutlet } from './utils/PrivateOutlet' function Hooray() { return ( diff --git a/examples/query/react/authentication-with-extrareducers/src/app/services/auth.ts b/examples/query/react/authentication-with-extrareducers/src/app/services/auth.ts index 371e6df347..9904691578 100644 --- a/examples/query/react/authentication-with-extrareducers/src/app/services/auth.ts +++ b/examples/query/react/authentication-with-extrareducers/src/app/services/auth.ts @@ -1,5 +1,5 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' -import { RootState } from '../store' +import type { RootState } from '../store' export interface User { first_name: string diff --git a/examples/query/react/authentication-with-extrareducers/src/features/auth/Login.tsx b/examples/query/react/authentication-with-extrareducers/src/features/auth/Login.tsx index ce36f9bbf0..3e6df53c89 100644 --- a/examples/query/react/authentication-with-extrareducers/src/features/auth/Login.tsx +++ b/examples/query/react/authentication-with-extrareducers/src/features/auth/Login.tsx @@ -1,21 +1,20 @@ -import * as React from 'react' import { + Box, + Button, + Center, + Divider, Input, InputGroup, InputRightElement, VStack, - Button, - Divider, - Center, - Box, useToast, } from '@chakra-ui/react' -import { useNavigate } from 'react-router-dom' +import * as React from 'react' import { useDispatch } from 'react-redux' - -import { ProtectedComponent } from './ProtectedComponent' -import { useLoginMutation } from '../../app/services/auth' +import { useNavigate } from 'react-router-dom' import type { LoginRequest } from '../../app/services/auth' +import { useLoginMutation } from '../../app/services/auth' +import { ProtectedComponent } from './ProtectedComponent' function PasswordInput({ name, diff --git a/examples/query/react/authentication-with-extrareducers/src/features/auth/ProtectedComponent.tsx b/examples/query/react/authentication-with-extrareducers/src/features/auth/ProtectedComponent.tsx index 1a63880717..d960b90993 100644 --- a/examples/query/react/authentication-with-extrareducers/src/features/auth/ProtectedComponent.tsx +++ b/examples/query/react/authentication-with-extrareducers/src/features/auth/ProtectedComponent.tsx @@ -1,4 +1,4 @@ -import { Center, VStack, Box, Button } from '@chakra-ui/react' +import { Box, Button, Center, VStack } from '@chakra-ui/react' import { useProtectedMutation } from '../../app/services/auth' export function ProtectedComponent() { diff --git a/examples/query/react/authentication-with-extrareducers/src/features/auth/authSlice.tsx b/examples/query/react/authentication-with-extrareducers/src/features/auth/authSlice.tsx index dfbc2182ec..bece91f99f 100644 --- a/examples/query/react/authentication-with-extrareducers/src/features/auth/authSlice.tsx +++ b/examples/query/react/authentication-with-extrareducers/src/features/auth/authSlice.tsx @@ -1,5 +1,6 @@ import { createSlice } from '@reduxjs/toolkit' -import { api, User } from '../../app/services/auth' +import type { User } from '../../app/services/auth' +import { api } from '../../app/services/auth' import type { RootState } from '../../app/store' type AuthState = { diff --git a/examples/query/react/authentication-with-extrareducers/src/hooks/store.ts b/examples/query/react/authentication-with-extrareducers/src/hooks/store.ts index 0be5471d1c..da9d6db3e1 100644 --- a/examples/query/react/authentication-with-extrareducers/src/hooks/store.ts +++ b/examples/query/react/authentication-with-extrareducers/src/hooks/store.ts @@ -1,4 +1,5 @@ -import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' +import type { TypedUseSelectorHook } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import type { AppDispatch, RootState } from '../app/store' export const useTypedSelector: TypedUseSelectorHook = useSelector diff --git a/examples/query/react/authentication-with-extrareducers/tsconfig.json b/examples/query/react/authentication-with-extrareducers/tsconfig.json index 2e7afa3896..6812fef180 100644 --- a/examples/query/react/authentication-with-extrareducers/tsconfig.json +++ b/examples/query/react/authentication-with-extrareducers/tsconfig.json @@ -1,20 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/authentication/package.json b/examples/query/react/authentication/package.json index e4a1e7a85f..11f223993c 100644 --- a/examples/query/react/authentication/package.json +++ b/examples/query/react/authentication/package.json @@ -20,9 +20,10 @@ "react-scripts": "5.0.1" }, "devDependencies": { + "@reduxjs/tsconfig": "workspace:^", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "scripts": { "start": "react-scripts start", diff --git a/examples/query/react/authentication/src/App.tsx b/examples/query/react/authentication/src/App.tsx index b5a6584be3..4313030b0a 100644 --- a/examples/query/react/authentication/src/App.tsx +++ b/examples/query/react/authentication/src/App.tsx @@ -1,9 +1,8 @@ -import { Routes, Route } from 'react-router-dom' import { Box, Center, VStack } from '@chakra-ui/react' - +import { Route, Routes } from 'react-router-dom' import { Login } from './features/auth/Login' -import { PrivateOutlet } from './utils/PrivateOutlet' import { ProtectedComponent } from './features/auth/ProtectedComponent' +import { PrivateOutlet } from './utils/PrivateOutlet' function Hooray() { return ( diff --git a/examples/query/react/authentication/src/app/services/auth.ts b/examples/query/react/authentication/src/app/services/auth.ts index 371e6df347..9904691578 100644 --- a/examples/query/react/authentication/src/app/services/auth.ts +++ b/examples/query/react/authentication/src/app/services/auth.ts @@ -1,5 +1,5 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' -import { RootState } from '../store' +import type { RootState } from '../store' export interface User { first_name: string diff --git a/examples/query/react/authentication/src/features/auth/Login.tsx b/examples/query/react/authentication/src/features/auth/Login.tsx index 9089dee33e..7aeca17b46 100644 --- a/examples/query/react/authentication/src/features/auth/Login.tsx +++ b/examples/query/react/authentication/src/features/auth/Login.tsx @@ -1,22 +1,21 @@ -import * as React from 'react' import { + Box, + Button, + Center, + Divider, Input, InputGroup, InputRightElement, VStack, - Button, - Divider, - Center, - Box, useToast, } from '@chakra-ui/react' -import { useNavigate } from 'react-router-dom' +import * as React from 'react' import { useDispatch } from 'react-redux' +import { useNavigate } from 'react-router-dom' +import type { LoginRequest } from '../../app/services/auth' +import { useLoginMutation } from '../../app/services/auth' import { setCredentials } from './authSlice' - import { ProtectedComponent } from './ProtectedComponent' -import { useLoginMutation } from '../../app/services/auth' -import type { LoginRequest } from '../../app/services/auth' function PasswordInput({ name, diff --git a/examples/query/react/authentication/src/features/auth/ProtectedComponent.tsx b/examples/query/react/authentication/src/features/auth/ProtectedComponent.tsx index 1a63880717..d960b90993 100644 --- a/examples/query/react/authentication/src/features/auth/ProtectedComponent.tsx +++ b/examples/query/react/authentication/src/features/auth/ProtectedComponent.tsx @@ -1,4 +1,4 @@ -import { Center, VStack, Box, Button } from '@chakra-ui/react' +import { Box, Button, Center, VStack } from '@chakra-ui/react' import { useProtectedMutation } from '../../app/services/auth' export function ProtectedComponent() { diff --git a/examples/query/react/authentication/src/hooks/store.ts b/examples/query/react/authentication/src/hooks/store.ts index 0be5471d1c..da9d6db3e1 100644 --- a/examples/query/react/authentication/src/hooks/store.ts +++ b/examples/query/react/authentication/src/hooks/store.ts @@ -1,4 +1,5 @@ -import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' +import type { TypedUseSelectorHook } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import type { AppDispatch, RootState } from '../app/store' export const useTypedSelector: TypedUseSelectorHook = useSelector diff --git a/examples/query/react/authentication/tsconfig.json b/examples/query/react/authentication/tsconfig.json index 2e7afa3896..6812fef180 100644 --- a/examples/query/react/authentication/tsconfig.json +++ b/examples/query/react/authentication/tsconfig.json @@ -1,20 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/basic/package.json b/examples/query/react/basic/package.json index a0a6290270..6d0a9eafad 100644 --- a/examples/query/react/basic/package.json +++ b/examples/query/react/basic/package.json @@ -13,13 +13,14 @@ "react-scripts": "5.0.1" }, "devDependencies": { - "@testing-library/dom": "^10.4.0", - "@testing-library/react": "^16.1.0", + "@reduxjs/tsconfig": "workspace:^", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.0", "@types/jest": "^26.0.23", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", "msw": "^0.40.2", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "eslintConfig": { "extends": [ diff --git a/examples/query/react/basic/src/test/test-utils.tsx b/examples/query/react/basic/src/test/test-utils.tsx index 714b2b6a51..0804b1676b 100644 --- a/examples/query/react/basic/src/test/test-utils.tsx +++ b/examples/query/react/basic/src/test/test-utils.tsx @@ -1,11 +1,11 @@ -import { render } from '@testing-library/react' +import type { PreloadedState } from '@reduxjs/toolkit' import type { RenderOptions } from '@testing-library/react' +import { render } from '@testing-library/react' import type React from 'react' -import type { PropsWithChildren, JSX } from 'react' +import type { JSX, PropsWithChildren } from 'react' import { Provider } from 'react-redux' -import { setupStore } from '../store' import type { AppStore, RootState } from '../store' -import type { PreloadedState } from '@reduxjs/toolkit' +import { setupStore } from '../store' // This type interface extends the default options for render from RTL, as well // as allows the user to specify other things such as initialState, store. For @@ -24,7 +24,7 @@ function renderWithProviders( ...renderOptions }: ExtendedRenderOptions = {}, ) { - function Wrapper({ children }: PropsWithChildren<{}>): JSX.Element { + function Wrapper({ children }: PropsWithChildren): JSX.Element { return {children} } return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) } diff --git a/examples/query/react/basic/tsconfig.json b/examples/query/react/basic/tsconfig.json index 2e7afa3896..6812fef180 100644 --- a/examples/query/react/basic/tsconfig.json +++ b/examples/query/react/basic/tsconfig.json @@ -1,20 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/conditional-fetching/package.json b/examples/query/react/conditional-fetching/package.json index 085da4166a..034c3fbff5 100644 --- a/examples/query/react/conditional-fetching/package.json +++ b/examples/query/react/conditional-fetching/package.json @@ -13,9 +13,10 @@ "react-scripts": "5.0.1" }, "devDependencies": { + "@reduxjs/tsconfig": "workspace:^", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "eslintConfig": { "extends": [ diff --git a/examples/query/react/conditional-fetching/src/App.tsx b/examples/query/react/conditional-fetching/src/App.tsx index 53c87863f3..43bd6643b8 100644 --- a/examples/query/react/conditional-fetching/src/App.tsx +++ b/examples/query/react/conditional-fetching/src/App.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import { Pokemon } from './Pokemon' -import { PokemonName, POKEMON_NAMES } from './pokemon.data' +import type { PokemonName } from './pokemon.data' +import { POKEMON_NAMES } from './pokemon.data' import './styles.css' const getRandomPokemonName = () => diff --git a/examples/query/react/conditional-fetching/tsconfig.json b/examples/query/react/conditional-fetching/tsconfig.json index 2e7afa3896..6812fef180 100644 --- a/examples/query/react/conditional-fetching/tsconfig.json +++ b/examples/query/react/conditional-fetching/tsconfig.json @@ -1,20 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/deduping-queries/package.json b/examples/query/react/deduping-queries/package.json index 210622c0b3..481a887a9c 100644 --- a/examples/query/react/deduping-queries/package.json +++ b/examples/query/react/deduping-queries/package.json @@ -13,9 +13,10 @@ "react-scripts": "5.0.1" }, "devDependencies": { + "@reduxjs/tsconfig": "workspace:^", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "eslintConfig": { "extends": [ diff --git a/examples/query/react/deduping-queries/tsconfig.json b/examples/query/react/deduping-queries/tsconfig.json index 2e7afa3896..6812fef180 100644 --- a/examples/query/react/deduping-queries/tsconfig.json +++ b/examples/query/react/deduping-queries/tsconfig.json @@ -1,20 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/graphql-codegen/package.json b/examples/query/react/graphql-codegen/package.json index 8acba56a08..0adcce8f03 100644 --- a/examples/query/react/graphql-codegen/package.json +++ b/examples/query/react/graphql-codegen/package.json @@ -33,6 +33,7 @@ "@graphql-codegen/typescript-operations": "^1.18.0", "@graphql-codegen/typescript-rtk-query": "^1.1.0", "@graphql-typed-document-node/core": "^3.1.0", + "@reduxjs/tsconfig": "workspace:^", "@types/faker": "^5.5.5", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", @@ -40,7 +41,7 @@ "concurrently": "^6.2.0", "cross-env": "^7.0.3", "ts-node": "^10.0.0", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "scripts": { "develop": "cross-env CHOKIDAR_USEPOLLING=true yarn start", diff --git a/examples/query/react/graphql-codegen/src/app/services/types.generated.ts b/examples/query/react/graphql-codegen/src/app/services/types.generated.ts index 399ebbd2c9..8300186423 100644 --- a/examples/query/react/graphql-codegen/src/app/services/types.generated.ts +++ b/examples/query/react/graphql-codegen/src/app/services/types.generated.ts @@ -1,5 +1,5 @@ export type Maybe = T -export type Exact = { +export type Exact> = { [K in keyof T]: T[K] } export type MakeOptional = Omit & { @@ -30,9 +30,9 @@ export type Mutation = { __typename?: 'Mutation' createPost?: Maybe updatePost?: Maybe - updatePosts?: Maybe>> + updatePosts?: Maybe[]> deletePost?: Maybe - deletePosts?: Maybe>> + deletePosts?: Maybe[]> } export type MutationCreatePostArgs = { @@ -94,7 +94,7 @@ export type PostQueryInput = { export type Query = { __typename?: 'Query' post?: Maybe - posts?: Maybe>> + posts?: Maybe[]> } export type QueryPostArgs = { diff --git a/examples/query/react/graphql-codegen/src/features/posts/PostsManager.tsx b/examples/query/react/graphql-codegen/src/features/posts/PostsManager.tsx index 82052c13f0..25f2773216 100644 --- a/examples/query/react/graphql-codegen/src/features/posts/PostsManager.tsx +++ b/examples/query/react/graphql-codegen/src/features/posts/PostsManager.tsx @@ -1,12 +1,11 @@ -import * as React from 'react' import { Badge, Box, Button, Divider, Flex, - Heading, HStack, + Heading, Icon, List, ListIcon, @@ -16,6 +15,7 @@ import { StatLabel, StatNumber, } from '@chakra-ui/react' +import * as React from 'react' import { MdArrowBack, MdArrowForward, MdBook } from 'react-icons/md' import { useGetPostsQuery } from './GetPosts.generated' diff --git a/examples/query/react/graphql-codegen/tsconfig.json b/examples/query/react/graphql-codegen/tsconfig.json index 4842cab6c4..6812fef180 100644 --- a/examples/query/react/graphql-codegen/tsconfig.json +++ b/examples/query/react/graphql-codegen/tsconfig.json @@ -1,21 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "baseUrl": "src" - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/graphql/package.json b/examples/query/react/graphql/package.json index ab6cee11a8..58f357e4e9 100644 --- a/examples/query/react/graphql/package.json +++ b/examples/query/react/graphql/package.json @@ -25,10 +25,11 @@ "react-scripts": "5.0.1" }, "devDependencies": { + "@reduxjs/tsconfig": "workspace:^", "@types/faker": "^5.5.5", "@types/react": "^19.0.1", "@types/react-dom": "^19.0.1", - "typescript": "^5.8.2" + "typescript": "^5.9.3" }, "scripts": { "start": "react-scripts start", diff --git a/examples/query/react/graphql/src/features/posts/PostsManager.tsx b/examples/query/react/graphql/src/features/posts/PostsManager.tsx index da92a4eea6..cbf74efb29 100644 --- a/examples/query/react/graphql/src/features/posts/PostsManager.tsx +++ b/examples/query/react/graphql/src/features/posts/PostsManager.tsx @@ -1,12 +1,11 @@ -import * as React from 'react' import { Badge, Box, Button, Divider, Flex, - Heading, HStack, + Heading, Icon, List, ListIcon, @@ -16,8 +15,10 @@ import { StatLabel, StatNumber, } from '@chakra-ui/react' +import * as React from 'react' import { MdArrowBack, MdArrowForward, MdBook } from 'react-icons/md' -import { Post, useGetPostsQuery } from '../../app/services/posts' +import type { Post } from '../../app/services/posts' +import { useGetPostsQuery } from '../../app/services/posts' const getColorForStatus = (status: Post['status']) => { return status === 'draft' diff --git a/examples/query/react/graphql/tsconfig.json b/examples/query/react/graphql/tsconfig.json index 2e7afa3896..6812fef180 100644 --- a/examples/query/react/graphql/tsconfig.json +++ b/examples/query/react/graphql/tsconfig.json @@ -1,20 +1,5 @@ { - "include": ["./src/**/*"], - "compilerOptions": { - "strict": true, - "esModuleInterop": true, - "lib": ["dom", "es2015"], - "jsx": "react-jsx", - "target": "es5", - "allowJs": true, - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - } + "extends": "@reduxjs/tsconfig/create-react-app", + "compilerOptions": {}, + "include": ["src"] } diff --git a/examples/query/react/infinite-queries/.eslintrc.json b/examples/query/react/infinite-queries/.eslintrc.json deleted file mode 100644 index e41a5aee79..0000000000 --- a/examples/query/react/infinite-queries/.eslintrc.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "react-app", - "plugin:react/jsx-runtime", - "prettier" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { "project": true, "tsconfigRootDir": "./" }, - "plugins": ["@typescript-eslint"], - "root": true, - "ignorePatterns": ["dist"], - "rules": { - "@typescript-eslint/consistent-type-imports": [ - 2, - { "fixStyle": "separate-type-imports" } - ], - "@typescript-eslint/no-restricted-imports": [ - 2, - { - "paths": [ - { - "name": "react-redux", - "importNames": ["useSelector", "useStore", "useDispatch"], - "message": "Please use pre-typed versions from `src/app/hooks.ts` instead." - } - ] - } - ] - }, - "overrides": [ - { "files": ["*.{c,m,}{t,j}s", "*.{t,j}sx"] }, - { "files": ["*{test,spec}.{t,j}s?(x)"], "env": { "jest": true } } - ] -} diff --git a/examples/query/react/infinite-queries/.prettierrc.json b/examples/query/react/infinite-queries/.prettierrc.json deleted file mode 100644 index 18b9c97f02..0000000000 --- a/examples/query/react/infinite-queries/.prettierrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "semi": false, - "arrowParens": "avoid" -} diff --git a/examples/query/react/infinite-queries/package.json b/examples/query/react/infinite-queries/package.json index 0644ea3adc..95404e28f8 100644 --- a/examples/query/react/infinite-queries/package.json +++ b/examples/query/react/infinite-queries/package.json @@ -6,16 +6,17 @@ "scripts": { "dev": "vite", "start": "vite", - "build": "tsc && vite build", + "build": "tsc -b && vite build", "preview": "vite preview", - "test": "vitest run", - "format": "prettier --write .", - "lint": "eslint .", - "lint:fix": "eslint --fix .", - "type-check": "tsc --noEmit" + "test": "yarn run -T test", + "format-check": "yarn run -T format-check", + "format": "yarn run -T format", + "lint-fix": "yarn run -T lint-fix", + "lint": "yarn run -T lint", + "type-check": "tsc -b --noEmit" }, "dependencies": { - "@reduxjs/toolkit": "https://pkg.csb.dev/reduxjs/redux-toolkit/commit/2aca4f24/@reduxjs/toolkit/_pkg.tgz", + "@reduxjs/toolkit": "workspace:^", "react": "^18.2.0", "react-dom": "^18.2.0", "react-intersection-observer": "^9.13.1", @@ -24,24 +25,27 @@ "react-router": "^7.0.1" }, "devDependencies": { - "@testing-library/dom": "^9.3.4", - "@testing-library/jest-dom": "^6.2.0", - "@testing-library/react": "^14.1.2", - "@testing-library/user-event": "^14.5.2", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", + "@reduxjs/eslint-config": "workspace:^", + "@reduxjs/prettier-config": "workspace:^", + "@reduxjs/tsconfig": "workspace:^", + "@reduxjs/vitest-config": "workspace:^", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", + "@types/node": "^24.9.1", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", "@types/react-native-web": "^0.19", "@vitejs/plugin-react": "^4.2.1", - "jsdom": "^23.2.0", + "eslint": "^9.38.0", + "jiti": "^2.6.1", + "jsdom": "^27.0.1", "msw": "^2.6.6", - "prettier": "^3.2.1", - "typescript": "^5.8.2", - "vite": "^5.0.0", - "vitest": "^1.2.0" - }, - "resolutions": { - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1" + "prettier": "^3.6.2", + "typescript": "^5.9.3", + "vite": "^7.1.11", + "vitest": "^3.2.4" }, "msw": { "workerDirectory": [ diff --git a/examples/query/react/infinite-queries/src/App.test.tsx b/examples/query/react/infinite-queries/src/App.test.tsx index 06b45be816..6dedd55ea0 100644 --- a/examples/query/react/infinite-queries/src/App.test.tsx +++ b/examples/query/react/infinite-queries/src/App.test.tsx @@ -1,105 +1,105 @@ -import { screen, waitFor } from "@testing-library/react" -import App from "./App" -import { renderWithProviders } from "./utils/test-utils" +import { screen, waitFor } from '@testing-library/react' +import App from './App' +import { renderWithProviders } from './utils/test-utils' -test("App should have correct initial render", () => { +test('App should have correct initial render', () => { renderWithProviders() // The app should be rendered correctly expect(screen.getByText(/learn/i)).toBeInTheDocument() // Initial state: count should be 0, incrementValue should be 2 - expect(screen.getByLabelText("Count")).toHaveTextContent("0") - expect(screen.getByLabelText("Set increment amount")).toHaveValue(2) + expect(screen.getByLabelText('Count')).toHaveTextContent('0') + expect(screen.getByLabelText('Set increment amount')).toHaveValue(2) }) -test("Increment value and Decrement value should work as expected", async () => { +test('Increment value and Decrement value should work as expected', async () => { const { user } = renderWithProviders() // Click on "+" => Count should be 1 - await user.click(screen.getByLabelText("Increment value")) - expect(screen.getByLabelText("Count")).toHaveTextContent("1") + await user.click(screen.getByLabelText('Increment value')) + expect(screen.getByLabelText('Count')).toHaveTextContent('1') // Click on "-" => Count should be 0 - await user.click(screen.getByLabelText("Decrement value")) - expect(screen.getByLabelText("Count")).toHaveTextContent("0") + await user.click(screen.getByLabelText('Decrement value')) + expect(screen.getByLabelText('Count')).toHaveTextContent('0') }) -test("Add Amount should work as expected", async () => { +test('Add Amount should work as expected', async () => { const { user } = renderWithProviders() // "Add Amount" button is clicked => Count should be 2 - await user.click(screen.getByText("Add Amount")) - expect(screen.getByLabelText("Count")).toHaveTextContent("2") + await user.click(screen.getByText('Add Amount')) + expect(screen.getByLabelText('Count')).toHaveTextContent('2') - const incrementValueInput = screen.getByLabelText("Set increment amount") + const incrementValueInput = screen.getByLabelText('Set increment amount') // incrementValue is 2, click on "Add Amount" => Count should be 4 await user.clear(incrementValueInput) - await user.type(incrementValueInput, "2") - await user.click(screen.getByText("Add Amount")) - expect(screen.getByLabelText("Count")).toHaveTextContent("4") + await user.type(incrementValueInput, '2') + await user.click(screen.getByText('Add Amount')) + expect(screen.getByLabelText('Count')).toHaveTextContent('4') // [Negative number] incrementValue is -1, click on "Add Amount" => Count should be 3 await user.clear(incrementValueInput) - await user.type(incrementValueInput, "-1") - await user.click(screen.getByText("Add Amount")) - expect(screen.getByLabelText("Count")).toHaveTextContent("3") + await user.type(incrementValueInput, '-1') + await user.click(screen.getByText('Add Amount')) + expect(screen.getByLabelText('Count')).toHaveTextContent('3') }) -it("Add Async should work as expected", async () => { +it('Add Async should work as expected', async () => { const { user } = renderWithProviders() // "Add Async" button is clicked => Count should be 2 - await user.click(screen.getByText("Add Async")) + await user.click(screen.getByText('Add Async')) await waitFor(() => - expect(screen.getByLabelText("Count")).toHaveTextContent("2"), + expect(screen.getByLabelText('Count')).toHaveTextContent('2'), ) - const incrementValueInput = screen.getByLabelText("Set increment amount") + const incrementValueInput = screen.getByLabelText('Set increment amount') // incrementValue is 2, click on "Add Async" => Count should be 4 await user.clear(incrementValueInput) - await user.type(incrementValueInput, "2") + await user.type(incrementValueInput, '2') - await user.click(screen.getByText("Add Async")) + await user.click(screen.getByText('Add Async')) await waitFor(() => - expect(screen.getByLabelText("Count")).toHaveTextContent("4"), + expect(screen.getByLabelText('Count')).toHaveTextContent('4'), ) // [Negative number] incrementValue is -1, click on "Add Async" => Count should be 3 await user.clear(incrementValueInput) - await user.type(incrementValueInput, "-1") - await user.click(screen.getByText("Add Async")) + await user.type(incrementValueInput, '-1') + await user.click(screen.getByText('Add Async')) await waitFor(() => - expect(screen.getByLabelText("Count")).toHaveTextContent("3"), + expect(screen.getByLabelText('Count')).toHaveTextContent('3'), ) }) -test("Add If Odd should work as expected", async () => { +test('Add If Odd should work as expected', async () => { const { user } = renderWithProviders() // "Add If Odd" button is clicked => Count should stay 0 - await user.click(screen.getByText("Add If Odd")) - expect(screen.getByLabelText("Count")).toHaveTextContent("0") + await user.click(screen.getByText('Add If Odd')) + expect(screen.getByLabelText('Count')).toHaveTextContent('0') // Click on "+" => Count should be updated to 1 - await user.click(screen.getByLabelText("Increment value")) - expect(screen.getByLabelText("Count")).toHaveTextContent("1") + await user.click(screen.getByLabelText('Increment value')) + expect(screen.getByLabelText('Count')).toHaveTextContent('1') // "Add If Odd" button is clicked => Count should be updated to 3 - await user.click(screen.getByText("Add If Odd")) - expect(screen.getByLabelText("Count")).toHaveTextContent("3") + await user.click(screen.getByText('Add If Odd')) + expect(screen.getByLabelText('Count')).toHaveTextContent('3') - const incrementValueInput = screen.getByLabelText("Set increment amount") + const incrementValueInput = screen.getByLabelText('Set increment amount') // incrementValue is 1, click on "Add If Odd" => Count should be updated to 4 await user.clear(incrementValueInput) - await user.type(incrementValueInput, "1") - await user.click(screen.getByText("Add If Odd")) - expect(screen.getByLabelText("Count")).toHaveTextContent("4") + await user.type(incrementValueInput, '1') + await user.click(screen.getByText('Add If Odd')) + expect(screen.getByLabelText('Count')).toHaveTextContent('4') // click on "Add If Odd" => Count should stay 4 await user.clear(incrementValueInput) - await user.type(incrementValueInput, "-1") - await user.click(screen.getByText("Add If Odd")) - expect(screen.getByLabelText("Count")).toHaveTextContent("4") + await user.type(incrementValueInput, '-1') + await user.click(screen.getByText('Add If Odd')) + expect(screen.getByLabelText('Count')).toHaveTextContent('4') }) diff --git a/examples/query/react/infinite-queries/src/App.tsx b/examples/query/react/infinite-queries/src/App.tsx index 77f4b56ff1..fad0401e9f 100644 --- a/examples/query/react/infinite-queries/src/App.tsx +++ b/examples/query/react/infinite-queries/src/App.tsx @@ -1,17 +1,17 @@ -import { BrowserRouter, Link, Route, Routes, useLocation } from "react-router" -import "./App.css" +import { BrowserRouter, Link, Route, Routes, useLocation } from 'react-router' +import './App.css' -import { Outlet } from "react-router" -import BidirectionalCursorInfScroll from "./features/bidirectional-cursor-infinite-scroll/BidirectionalCursorInfScroll" +import { Outlet } from 'react-router' +import BidirectionalCursorInfScroll from './features/bidirectional-cursor-infinite-scroll/BidirectionalCursorInfScroll' import { InfiniteScrollAbout, InfiniteScrollExample, -} from "./features/infinite-scroll/InfiniteScrollExample" -import LimitOffsetExample from "./features/limit-offset/LimitOffsetExample" -import { InfiniteScrollMaxPagesExample } from "./features/max-pages/InfiniteScrollMaxExample" -import PaginationInfScrollExample from "./features/pagination-infinite-scroll/PaginationInfScrollExample" -import { PaginationExample } from "./features/pagination/PaginationExample" -import { FlatlistExample } from "./features/rn-flatlist/FlatlistExample" +} from './features/infinite-scroll/InfiniteScrollExample' +import LimitOffsetExample from './features/limit-offset/LimitOffsetExample' +import { InfiniteScrollMaxPagesExample } from './features/max-pages/InfiniteScrollMaxExample' +import PaginationInfScrollExample from './features/pagination-infinite-scroll/PaginationInfScrollExample' +import { PaginationExample } from './features/pagination/PaginationExample' +import { FlatlistExample } from './features/rn-flatlist/FlatlistExample' const Menu = () => { return ( diff --git a/examples/query/react/infinite-queries/src/app/createAppSlice.ts b/examples/query/react/infinite-queries/src/app/createAppSlice.ts index 64afebbb60..7f0601350d 100644 --- a/examples/query/react/infinite-queries/src/app/createAppSlice.ts +++ b/examples/query/react/infinite-queries/src/app/createAppSlice.ts @@ -1,4 +1,4 @@ -import { asyncThunkCreator, buildCreateSlice } from "@reduxjs/toolkit" +import { asyncThunkCreator, buildCreateSlice } from '@reduxjs/toolkit' // `buildCreateSlice` allows us to create a slice with async thunks. export const createAppSlice = buildCreateSlice({ diff --git a/examples/query/react/infinite-queries/src/app/hooks.ts b/examples/query/react/infinite-queries/src/app/hooks.ts index bc8990df57..2706f2c627 100644 --- a/examples/query/react/infinite-queries/src/app/hooks.ts +++ b/examples/query/react/infinite-queries/src/app/hooks.ts @@ -3,9 +3,9 @@ // usage of typed hooks throughout the application. // We disable the ESLint rule here because this is the designated place // for importing and re-exporting the typed versions of hooks. -/* eslint-disable @typescript-eslint/no-restricted-imports */ -import { useDispatch, useSelector } from "react-redux" -import type { AppDispatch, RootState } from "./store" + +import { useDispatch, useSelector } from 'react-redux' +import type { AppDispatch, RootState } from './store' // Use throughout your app instead of plain `useDispatch` and `useSelector` export const useAppDispatch = useDispatch.withTypes() diff --git a/examples/query/react/infinite-queries/src/app/store.ts b/examples/query/react/infinite-queries/src/app/store.ts index f71a782819..743509b72e 100644 --- a/examples/query/react/infinite-queries/src/app/store.ts +++ b/examples/query/react/infinite-queries/src/app/store.ts @@ -1,7 +1,7 @@ -import type { Action, ThunkAction } from "@reduxjs/toolkit" -import { combineSlices, configureStore } from "@reduxjs/toolkit" -import { setupListeners } from "@reduxjs/toolkit/query" -import { baseApi } from "../features/baseApi" +import type { Action, ThunkAction } from '@reduxjs/toolkit' +import { combineSlices, configureStore } from '@reduxjs/toolkit' +import { setupListeners } from '@reduxjs/toolkit/query' +import { baseApi } from '../features/baseApi' // `combineSlices` automatically combines the reducers using // their `reducerPath`s, therefore we no longer need to call `combineReducers`. @@ -16,7 +16,7 @@ export const makeStore = (preloadedState?: Partial) => { reducer: rootReducer, // Adding the api middleware enables caching, invalidation, polling, // and other useful features of `rtk-query`. - middleware: getDefaultMiddleware => { + middleware: (getDefaultMiddleware) => { return getDefaultMiddleware().concat(baseApi.middleware) }, preloadedState, @@ -32,7 +32,7 @@ export const store = makeStore() // Infer the type of `store` export type AppStore = typeof store // Infer the `AppDispatch` type from the store itself -export type AppDispatch = AppStore["dispatch"] +export type AppDispatch = AppStore['dispatch'] export type AppThunk = ThunkAction< ThunkReturnType, RootState, diff --git a/examples/query/react/infinite-queries/src/app/useIntersectionCallback.ts b/examples/query/react/infinite-queries/src/app/useIntersectionCallback.ts index 63834f0cef..f17c6aba50 100644 --- a/examples/query/react/infinite-queries/src/app/useIntersectionCallback.ts +++ b/examples/query/react/infinite-queries/src/app/useIntersectionCallback.ts @@ -1,4 +1,4 @@ -import { useCallback, useRef } from "react" +import { useCallback, useRef } from 'react' export function useIntersectionCallback(onIntersectCallback: () => void) { const intersectionObserverRef = useRef(null) @@ -9,7 +9,7 @@ export function useIntersectionCallback(onIntersectCallback: () => void) { intersectionObserverRef.current.disconnect() } - intersectionObserverRef.current = new IntersectionObserver(entries => { + intersectionObserverRef.current = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { onIntersectCallback() } diff --git a/examples/query/react/infinite-queries/src/features/baseApi.ts b/examples/query/react/infinite-queries/src/features/baseApi.ts index 9f460f1a8c..5147293039 100644 --- a/examples/query/react/infinite-queries/src/features/baseApi.ts +++ b/examples/query/react/infinite-queries/src/features/baseApi.ts @@ -1,6 +1,6 @@ -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react" +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' export const baseApi = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: "/" }), - endpoints: build => ({}), + baseQuery: fetchBaseQuery({ baseUrl: '/' }), + endpoints: (build) => ({}), }) diff --git a/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/BidirectionalCursorInfScroll.tsx b/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/BidirectionalCursorInfScroll.tsx index 5011057290..21c9fb73e5 100644 --- a/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/BidirectionalCursorInfScroll.tsx +++ b/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/BidirectionalCursorInfScroll.tsx @@ -1,7 +1,7 @@ -import React, { useCallback, useEffect, useRef, useState } from "react" -import { Link, useLocation } from "react-router" -import { useIntersectionCallback } from "../../app/useIntersectionCallback" -import { apiWithInfiniteScroll } from "./infiniteScrollApi" +import React, { useCallback, useEffect, useRef, useState } from 'react' +import { Link, useLocation } from 'react-router' +import { useIntersectionCallback } from '../../app/useIntersectionCallback' +import { apiWithInfiniteScroll } from './infiniteScrollApi' const limit = 10 @@ -42,8 +42,8 @@ function BidirectionalCursorInfScroll({ startingProject = { id: 25 } }) { const startingElement = startingProjectRef.current if (startingElement) { startingElement.scrollIntoView({ - behavior: "auto", - block: "center", + behavior: 'auto', + block: 'center', }) setHasCentered(true) } @@ -64,30 +64,30 @@ function BidirectionalCursorInfScroll({ startingProject = { id: 25 } }) { disabled={!hasPreviousPage || isFetchingPreviousPage} > {isFetchingPreviousPage - ? "Loading more..." + ? 'Loading more...' : hasPreviousPage - ? "Load Older" - : "Nothing more to load"} + ? 'Load Older' + : 'Nothing more to load'}
- {data?.pages.map(page => ( + {data?.pages.map((page) => ( {page.projects.map((project, index, arr) => { return (
{isFetchingNextPage - ? "Loading more..." + ? 'Loading more...' : hasNextPage - ? "Load Newer" - : "Nothing more to load"} + ? 'Load Newer' + : 'Nothing more to load'}
{isFetching && !isFetchingPreviousPage && !isFetchingNextPage - ? "Background Updating..." + ? 'Background Updating...' : null}
diff --git a/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/infiniteScrollApi.ts b/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/infiniteScrollApi.ts index dc4b68ddab..44ed0fbbd7 100644 --- a/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/infiniteScrollApi.ts +++ b/examples/query/react/infinite-queries/src/features/bidirectional-cursor-infinite-scroll/infiniteScrollApi.ts @@ -1,4 +1,4 @@ -import { baseApi } from "../baseApi" +import { baseApi } from '../baseApi' type Project = { id: number @@ -25,7 +25,7 @@ type ProjectsInitialPageParam = { type QueryParamLimit = number export const apiWithInfiniteScroll = baseApi.injectEndpoints({ - endpoints: build => ({ + endpoints: (build) => ({ getProjectsBidirectionalCursor: build.infiniteQuery< ProjectsCursorPaginated, QueryParamLimit, @@ -33,13 +33,13 @@ export const apiWithInfiniteScroll = baseApi.injectEndpoints({ >({ query: ({ pageParam: { before, after, around, limit } }) => { const params = new URLSearchParams() - params.append("limit", String(limit)) + params.append('limit', String(limit)) if (after != null) { - params.append("after", String(after)) + params.append('after', String(after)) } else if (before != null) { - params.append("before", String(before)) + params.append('before', String(before)) } else if (around != null) { - params.append("around", String(around)) + params.append('around', String(around)) } return { diff --git a/examples/query/react/infinite-queries/src/features/infinite-scroll/InfiniteScrollExample.tsx b/examples/query/react/infinite-queries/src/features/infinite-scroll/InfiniteScrollExample.tsx index e8b738a255..10adfa2a71 100644 --- a/examples/query/react/infinite-queries/src/features/infinite-scroll/InfiniteScrollExample.tsx +++ b/examples/query/react/infinite-queries/src/features/infinite-scroll/InfiniteScrollExample.tsx @@ -1,15 +1,15 @@ -import React from "react" -import { useInView } from "react-intersection-observer" -import { Link } from "react-router" +import React from 'react' +import { useInView } from 'react-intersection-observer' +import { Link } from 'react-router' -import { apiWithInfiniteScroll } from "./infiniteScrollApi" -import type { Project } from "./infiniteScrollApi" +import { apiWithInfiniteScroll } from './infiniteScrollApi' +import type { Project } from './infiniteScrollApi' export const InfiniteScrollAbout = () => { return ( { + onClick={(e) => { window.history.back() e.preventDefault() }} @@ -23,9 +23,9 @@ export const ProjectRow = ({ project }: { project: Project }) => { return (

{ isError, } = apiWithInfiniteScroll.endpoints.getProjectsCursor.useInfiniteQuery( - "projects", + 'projects', ) const { ref, inView } = useInView() React.useEffect(() => { if (inView) { - console.log("Fetching next page") + console.log('Fetching next page') fetchNextPage() } }, [fetchNextPage, inView]) @@ -81,9 +81,9 @@ export const InfiniteScrollExample = () => { : "Nothing more to load"} */}

- {data?.pages.map(page => ( + {data?.pages.map((page) => ( - {page.projects.map(project => ( + {page.projects.map((project) => ( ))} @@ -95,13 +95,13 @@ export const InfiniteScrollExample = () => { disabled={!hasNextPage || isFetchingNextPage} > {isFetchingNextPage - ? "Loading more..." + ? 'Loading more...' : hasNextPage - ? "Load Newer" - : "Nothing more to load"} + ? 'Load Newer' + : 'Nothing more to load'}
-
{isFetching ? "Background Updating..." : null}
+
{isFetching ? 'Background Updating...' : null}
}
diff --git a/examples/query/react/infinite-queries/src/features/infinite-scroll/infiniteScrollApi.ts b/examples/query/react/infinite-queries/src/features/infinite-scroll/infiniteScrollApi.ts index c543d44f1d..7317fa6c03 100644 --- a/examples/query/react/infinite-queries/src/features/infinite-scroll/infiniteScrollApi.ts +++ b/examples/query/react/infinite-queries/src/features/infinite-scroll/infiniteScrollApi.ts @@ -1,4 +1,4 @@ -import { baseApi } from "../baseApi" +import { baseApi } from '../baseApi' export type Project = { id: number @@ -12,13 +12,13 @@ type ProjectsPageCursor = { } export const apiWithInfiniteScroll = baseApi.injectEndpoints({ - endpoints: build => ({ + endpoints: (build) => ({ getProjectsCursor: build.infiniteQuery({ query: ({ pageParam }) => `https://example.com/api/projectsCursor?cursor=${pageParam}`, infiniteQueryOptions: { initialPageParam: 0, - getPreviousPageParam: firstPage => firstPage.previousId, + getPreviousPageParam: (firstPage) => firstPage.previousId, getNextPageParam: ( lastPage, allPages, diff --git a/examples/query/react/infinite-queries/src/features/limit-offset/LimitOffsetExample.tsx b/examples/query/react/infinite-queries/src/features/limit-offset/LimitOffsetExample.tsx index 9610879fb2..cf421784cb 100644 --- a/examples/query/react/infinite-queries/src/features/limit-offset/LimitOffsetExample.tsx +++ b/examples/query/react/infinite-queries/src/features/limit-offset/LimitOffsetExample.tsx @@ -1,11 +1,12 @@ -import { createSelector } from "@reduxjs/toolkit" -import { +import { createSelector } from '@reduxjs/toolkit' +import type { BaseQueryFn, TypedUseQueryStateResult, -} from "@reduxjs/toolkit/query/react" -import { Link, useLocation } from "react-router" -import { useIntersectionCallback } from "../../app/useIntersectionCallback" -import { apiWithInfiniteScroll, ProjectsResponse } from "./infiniteScrollApi" +} from '@reduxjs/toolkit/query/react' +import { Link, useLocation } from 'react-router' +import { useIntersectionCallback } from '../../app/useIntersectionCallback' +import type { ProjectsResponse } from './infiniteScrollApi' +import { apiWithInfiniteScroll } from './infiniteScrollApi' type ProjectsInfiniteQueryResult = TypedUseQueryStateResult< { pages: ProjectsResponse[] }, @@ -17,7 +18,7 @@ const selectCombinedProjects = createSelector( (res: ProjectsInfiniteQueryResult) => { return res.data }, - data => data?.pages?.map(item => item?.projects)?.flat(), + (data) => data?.pages?.map((item) => item?.projects)?.flat(), ) function LimitOffsetExample() { @@ -37,7 +38,7 @@ function LimitOffsetExample() { } = apiWithInfiniteScroll.endpoints.projectsLimitOffset.useInfiniteQuery( undefined, { - selectFromResult: result => { + selectFromResult: (result) => { return { ...result, combinedData: selectCombinedProjects(result), @@ -65,27 +66,27 @@ function LimitOffsetExample() { disabled={!hasPreviousPage || isFetchingPreviousPage} > {isFetchingPreviousPage - ? "Loading more..." + ? 'Loading more...' : hasPreviousPage - ? "Load Older" - : "Nothing more to load"} + ? 'Load Older' + : 'Nothing more to load'}
{combinedData?.map((project, index, arr) => { return (
{isFetchingNextPage - ? "Loading more..." + ? 'Loading more...' : hasNextPage - ? "Load Newer" - : "Nothing more to load"} + ? 'Load Newer' + : 'Nothing more to load'}
{isFetching && !isFetchingPreviousPage && !isFetchingNextPage - ? "Background Updating..." + ? 'Background Updating...' : null}
diff --git a/examples/query/react/infinite-queries/src/features/limit-offset/infiniteScrollApi.ts b/examples/query/react/infinite-queries/src/features/limit-offset/infiniteScrollApi.ts index 97aae393e5..e4458dfb9c 100644 --- a/examples/query/react/infinite-queries/src/features/limit-offset/infiniteScrollApi.ts +++ b/examples/query/react/infinite-queries/src/features/limit-offset/infiniteScrollApi.ts @@ -1,4 +1,4 @@ -import { baseApi } from "../baseApi" +import { baseApi } from '../baseApi' type Project = { id: number @@ -17,7 +17,7 @@ type ProjectsInitialPageParam = { } export const apiWithInfiniteScroll = baseApi.injectEndpoints({ - endpoints: build => ({ + endpoints: (build) => ({ projectsLimitOffset: build.infiniteQuery< ProjectsResponse, void, diff --git a/examples/query/react/infinite-queries/src/features/max-pages/InfiniteScrollMaxExample.tsx b/examples/query/react/infinite-queries/src/features/max-pages/InfiniteScrollMaxExample.tsx index f91c47e0e3..947afd8fa6 100644 --- a/examples/query/react/infinite-queries/src/features/max-pages/InfiniteScrollMaxExample.tsx +++ b/examples/query/react/infinite-queries/src/features/max-pages/InfiniteScrollMaxExample.tsx @@ -1,5 +1,5 @@ -import React from "react" -import { apiWithInfiniteScrollMax } from "./infiniteScrollApi" +import React from 'react' +import { apiWithInfiniteScrollMax } from './infiniteScrollApi' export const InfiniteScrollMaxPagesExample = () => { const { @@ -13,7 +13,7 @@ export const InfiniteScrollMaxPagesExample = () => { isError, } = apiWithInfiniteScrollMax.endpoints.getProjectsCursorMax.useInfiniteQuery( - "projects", + 'projects', ) // TODO This should be built in to RTKQ @@ -38,19 +38,19 @@ export const InfiniteScrollMaxPagesExample = () => { { /*isFetchingPreviousPage ? 'Loading more...' - :*/ hasPreviousPage ? "Load Older" : "Nothing more to load" + :*/ hasPreviousPage ? 'Load Older' : 'Nothing more to load' }
- {data?.pages.map(page => ( + {data?.pages.map((page) => ( - {page.projects.map(project => ( + {page.projects.map((project) => (

{ disabled={!hasNextPage /* || isFetchingNextPage*/} > {isFetchingNextPage - ? "Loading more..." + ? 'Loading more...' : hasNextPage - ? "Load Newer" - : "Nothing more to load"} + ? 'Load Newer' + : 'Nothing more to load'}

{isFetching && !isFetchingNextPage - ? "Background Updating..." + ? 'Background Updating...' : null}
diff --git a/examples/query/react/infinite-queries/src/features/max-pages/infiniteScrollApi.ts b/examples/query/react/infinite-queries/src/features/max-pages/infiniteScrollApi.ts index 3a6247ea10..a891478f6e 100644 --- a/examples/query/react/infinite-queries/src/features/max-pages/infiniteScrollApi.ts +++ b/examples/query/react/infinite-queries/src/features/max-pages/infiniteScrollApi.ts @@ -1,4 +1,4 @@ -import { baseApi } from "../baseApi" +import { baseApi } from '../baseApi' type Project = { id: number @@ -12,7 +12,7 @@ type ProjectsPageCursor = { } export const apiWithInfiniteScrollMax = baseApi.injectEndpoints({ - endpoints: build => ({ + endpoints: (build) => ({ getProjectsCursorMax: build.infiniteQuery< ProjectsPageCursor, string, @@ -23,8 +23,8 @@ export const apiWithInfiniteScrollMax = baseApi.injectEndpoints({ infiniteQueryOptions: { initialPageParam: 0, maxPages: 3, - getPreviousPageParam: firstPage => firstPage.previousId ?? undefined, - getNextPageParam: lastPage => lastPage.nextId ?? undefined, + getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined, + getNextPageParam: (lastPage) => lastPage.nextId ?? undefined, }, }), }), diff --git a/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/PaginationInfScrollExample.tsx b/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/PaginationInfScrollExample.tsx index c461b0a09c..36a6ba8227 100644 --- a/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/PaginationInfScrollExample.tsx +++ b/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/PaginationInfScrollExample.tsx @@ -1,11 +1,12 @@ -import { createSelector } from "@reduxjs/toolkit" -import { +import { createSelector } from '@reduxjs/toolkit' +import type { BaseQueryFn, TypedUseQueryStateResult, -} from "@reduxjs/toolkit/query/react" -import { Link, useLocation } from "react-router" -import { useIntersectionCallback } from "../../app/useIntersectionCallback" -import { apiWithInfiniteScroll, ProjectsResponse } from "./infiniteScrollApi" +} from '@reduxjs/toolkit/query/react' +import { Link, useLocation } from 'react-router' +import { useIntersectionCallback } from '../../app/useIntersectionCallback' +import type { ProjectsResponse } from './infiniteScrollApi' +import { apiWithInfiniteScroll } from './infiniteScrollApi' type ProjectsInfiniteQueryResult = TypedUseQueryStateResult< { pages: ProjectsResponse[] }, @@ -17,7 +18,7 @@ const selectCombinedProjects = createSelector( (res: ProjectsInfiniteQueryResult) => { return res.data }, - data => data?.pages?.map(item => item?.projects)?.flat(), + (data) => data?.pages?.map((item) => item?.projects)?.flat(), ) function PaginationInfScrollExample() { @@ -37,7 +38,7 @@ function PaginationInfScrollExample() { } = apiWithInfiniteScroll.endpoints.projectsPaginated.useInfiniteQuery( undefined, { - selectFromResult: result => { + selectFromResult: (result) => { return { ...result, combinedData: selectCombinedProjects(result), @@ -65,27 +66,27 @@ function PaginationInfScrollExample() { disabled={!hasPreviousPage || isFetchingPreviousPage} > {isFetchingPreviousPage - ? "Loading more..." + ? 'Loading more...' : hasPreviousPage - ? "Load Older" - : "Nothing more to load"} + ? 'Load Older' + : 'Nothing more to load'}
{combinedData?.map((project, index, arr) => { return (
{isFetchingNextPage - ? "Loading more..." + ? 'Loading more...' : hasNextPage - ? "Load Newer" - : "Nothing more to load"} + ? 'Load Newer' + : 'Nothing more to load'}
{isFetching && !isFetchingPreviousPage && !isFetchingNextPage - ? "Background Updating..." + ? 'Background Updating...' : null}
diff --git a/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/infiniteScrollApi.ts b/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/infiniteScrollApi.ts index eaa463f169..549891dde4 100644 --- a/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/infiniteScrollApi.ts +++ b/examples/query/react/infinite-queries/src/features/pagination-infinite-scroll/infiniteScrollApi.ts @@ -1,4 +1,4 @@ -import { baseApi } from "../baseApi" +import { baseApi } from '../baseApi' type Project = { id: number @@ -17,7 +17,7 @@ interface ProjectsInitialPageParam { } export const apiWithInfiniteScroll = baseApi.injectEndpoints({ - endpoints: build => ({ + endpoints: (build) => ({ projectsPaginated: build.infiniteQuery< ProjectsResponse, void, @@ -64,7 +64,7 @@ export const apiWithInfiniteScroll = baseApi.injectEndpoints({ query: ({ pageParam: { page, size } }) => { return { url: `https://example.com/api/projectsPaginated?page=${page}&size=${size}`, - method: "GET", + method: 'GET', } }, }), diff --git a/examples/query/react/infinite-queries/src/features/pagination/PaginationExample.tsx b/examples/query/react/infinite-queries/src/features/pagination/PaginationExample.tsx index d0c46fd68a..3e4bd887f0 100644 --- a/examples/query/react/infinite-queries/src/features/pagination/PaginationExample.tsx +++ b/examples/query/react/infinite-queries/src/features/pagination/PaginationExample.tsx @@ -1,5 +1,5 @@ -import React from "react" -import { apiWithPagination } from "./paginationApi" +import React from 'react' +import { apiWithPagination } from './paginationApi' // The React Query example actually just uses a normal query // rather than an infinite query, and Dominik confirmed that @@ -19,7 +19,7 @@ export const PaginationExample = () => { isFetchingNextPage, isFetching, isError, - } = apiWithPagination.endpoints.getProjects.useInfiniteQuery("projects") + } = apiWithPagination.endpoints.getProjects.useInfiniteQuery('projects') const currentPage = data?.pages[page] @@ -29,15 +29,15 @@ export const PaginationExample = () => {
Current Page: {page + 1}
{" "} + {' '}