Skip to content

Commit e5a7f36

Browse files
committed
chore: update TypeScript to v6.0
- Update TypeScript version to [v6.0](https://devblogs.microsoft.com/typescript/announcing-typescript-6-0). - Raise the minimum supported TypeScript version to [v5.5](https://devblogs.microsoft.com/typescript/announcing-typescript-5-5) (drop `5.0`-`5.4`).
1 parent 4b49bf1 commit e5a7f36

36 files changed

Lines changed: 10223 additions & 11677 deletions

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ jobs:
119119
fail-fast: false
120120
matrix:
121121
node: ['24.x']
122-
ts: ['5.5', '5.6', '5.7', '5.8']
122+
ts: ['5.5', '5.6', '5.7', '5.8', '5.9', '6.0']
123123
steps:
124124
- name: Checkout repo
125125
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import React from 'react'
1+
import type { FC, PropsWithChildren } from 'react'
22

3-
export const DetailedExplanation = ({
3+
export const DetailedExplanation: FC<PropsWithChildren<{ title?: string }>> = ({
44
children,
55
title = 'Detailed Explanation'
66
}) => {

docs/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
{
22
"devDependencies": {
33
"@reduxjs/toolkit": "^2.0.1",
4+
"@testing-library/jest-dom": "^6.9.1",
45
"@testing-library/react": "^14.1.2",
6+
"@testing-library/user-event": "^14.6.1",
7+
"@types/node": "^25.9.3",
58
"@vitest/browser-playwright": "^4.0.5",
69
"msw": "^2.0.0",
710
"react": "^18.2.0",

docs/tutorials/essentials/part-3-data-flow.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,8 @@ When we write the `postAdded` reducer function, `createSlice` will automatically
508508
```ts title="features/posts/postsSlice.ts"
509509
// highlight-start
510510
// Import the `PayloadAction` TS type
511-
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
511+
import type { PayloadAction } from '@reduxjs/toolkit'
512+
import { createSlice } from '@reduxjs/toolkit'
512513
// highlight-end
513514

514515
// omit initial state

docs/tutorials/essentials/part-4-using-data.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ Given all those requirements, here's how our `postsSlice` definition should look
215215

216216
```ts title="features/posts/postsSlice.ts"
217217
// highlight-next-line
218-
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
218+
import type { PayloadAction } from '@reduxjs/toolkit'
219+
import { createSlice } from '@reduxjs/toolkit'
219220

220221
// omit state types
221222

@@ -599,7 +600,8 @@ You can't have a "social media" app if there aren't any other people involved! L
599600
Since the concept of "users" is different than the concept of "posts", we want to keep the code and data for the users separated from the code and data for posts. We'll add a new `features/users` folder, and put a `usersSlice` file in there. Like with the posts slice, for now we'll add some initial entries so that we have data to work with.
600601
601602
```ts title="features/users/usersSlice.ts"
602-
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
603+
import type { PayloadAction } from '@reduxjs/toolkit'
604+
import { createSlice } from '@reduxjs/toolkit'
603605

604606
import type { RootState } from '@/app/store'
605607

@@ -926,7 +928,8 @@ Then, we can define a new reducer that will handle updating the reaction count f
926928
Like with editing posts, we need to know the ID of the post, and which reaction button the user clicked on. We'll have our `action.payload` be an object that looks like `{id, reaction}`. The reducer can then find the right post object, and update the correct reactions field.
927929
928930
```ts title="features/posts/postsSlice.ts"
929-
import { createSlice, nanoid, PayloadAction } from '@reduxjs/toolkit'
931+
import type { PayloadAction } from '@reduxjs/toolkit'
932+
import { createSlice, nanoid } from '@reduxjs/toolkit'
930933
import { sub } from 'date-fns'
931934

932935
// highlight-start
@@ -1066,7 +1069,8 @@ The first step is to create the `authSlice` and add it to the store. This is the
10661069
In this case, our auth state is really just the current logged-in username, and we'll reset it to `null` if they log out.
10671070
10681071
```ts title="features/auth/authSlice.ts"
1069-
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
1072+
import type { PayloadAction } from '@reduxjs/toolkit'
1073+
import { createSlice } from '@reduxjs/toolkit'
10701074

10711075
interface AuthState {
10721076
username: string | null
@@ -1436,7 +1440,8 @@ You can chain these together, like `builder.addCase().addCase().addMatcher().add
14361440
Given that, we can import the `userLoggedOut` action from `authSlice.ts` into `postsSlice.ts`, listen for that action inside of `postsSlice.extraReducers`, and return an empty posts array to reset the posts list on logout:
14371441
14381442
```ts title="features/posts/postsSlice.ts"
1439-
import { createSlice, nanoid, PayloadAction } from '@reduxjs/toolkit'
1443+
import type { PayloadAction } from '@reduxjs/toolkit'
1444+
import { createSlice, nanoid } from '@reduxjs/toolkit'
14401445
import { sub } from 'date-fns'
14411446

14421447
// highlight-next-line

docs/tutorials/essentials/part-5-async-logic.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ Redux Toolkit's `createAsyncThunk` API generates thunks that automatically dispa
408408
Let's start by adding a thunk that will make an HTTP request to retrieve a list of posts. We'll import the `client` utility from the `src/api` folder, and use that to make a request to `'/fakeApi/posts'`.
409409

410410
```ts title="features/posts/postsSlice.ts"
411-
import { createSlice, nanoid, PayloadAction } from '@reduxjs/toolkit'
411+
import type { PayloadAction } from '@reduxjs/toolkit'
412+
import { createSlice, nanoid } from '@reduxjs/toolkit'
412413
// highlight-next-line
413414
import { client } from '@/api/client'
414415

@@ -891,7 +892,8 @@ This is because the post entries are being randomly generated by the fake API se
891892
Like last time, we'll create another async thunk to get the users from the API and return them, then handle the `fulfilled` action in the `extraReducers` slice field. We'll skip worrying about loading state for now:
892893

893894
```ts title="features/users/usersSlice.ts"
894-
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
895+
import type { PayloadAction } from '@reduxjs/toolkit'
896+
import { createSlice } from '@reduxjs/toolkit'
895897

896898
// highlight-next-line
897899
import { client } from '@/api/client'

docs/tutorials/essentials/part-6-performance-normalization.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ export const Navbar = () => {
265265
// highlight-next-line
266266
dispatch(logout())
267267
}
268+
}
269+
}
268270
```
269271

270272
```tsx title="features/auth/LoginPage.tsx"
@@ -293,14 +295,14 @@ export const LoginPage = () => {
293295
await dispatch(login(username))
294296
navigate('/posts')
295297
}
296-
297298
```
298299
299300
Since the `userLoggedOut` action creator was being used by the `postsSlice`, we can update that to listen to `logout.fulfilled` instead:
300301
301302
```ts title="features/posts/postsSlice.ts"
302-
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
303303
import { client } from '@/api/client'
304+
import type { PayloadAction } from '@reduxjs/toolkit'
305+
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
304306

305307
import type { RootState } from '@/app/store'
306308

@@ -1504,18 +1506,17 @@ Now we can go add a listener that will watch for the `addNewPost.fulfilled` acti
15041506
There's [multiple approaches we can use for defining listeners in our codebase](https://redux-toolkit.js.org/api/createListenerMiddleware#organizing-listeners-in-files). That said, it's usually a good practice to define listeners in whatever slice file seems most related to the logic we want to add. In this case, we want to show a toast when a post gets added, so let's add this listener in the `postsSlice` file:
15051507
15061508
```ts title="features/posts/postsSlice.ts"
1509+
import type { EntityState, PayloadAction } from '@reduxjs/toolkit'
15071510
import {
15081511
createEntityAdapter,
15091512
createSelector,
1510-
createSlice,
1511-
EntityState,
1512-
PayloadAction
1513+
createSlice
15131514
} from '@reduxjs/toolkit'
15141515
import { client } from '@/api/client'
15151516

15161517
import type { RootState } from '@/app/store'
15171518
// highlight-next-line
1518-
import { AppStartListening } from '@/app/listenerMiddleware'
1519+
import type { AppStartListening } from '@/app/listenerMiddleware'
15191520
import { createAppAsyncThunk } from '@/app/withTypes'
15201521

15211522
// omit types, initial state, slice definition, and selectors

docs/tutorials/essentials/part-7-rtk-query-basics.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ import { DetailedExplanation } from '../../components/DetailedExplanation'
2626
If you prefer a video course, you can [watch this RTK Query video course by Lenz Weber-Tronic, the creator of RTK Query, for free at Egghead](https://egghead.io/courses/rtk-query-basics-query-endpoints-data-flow-and-typescript-57ea3c43?af=7pnhj6) or take a look at the first lesson right here:
2727

2828
<div style={{position:"relative",paddingTop:"56.25%"}}>
29-
<iframe
30-
src="https://app.egghead.io/lessons/redux-course-introduction-and-application-walk-through-for-rtk-query-basics/embed?af=7pnhj6"
29+
<iframe
30+
src="https://app.egghead.io/lessons/redux-course-introduction-and-application-walk-through-for-rtk-query-basics/embed?af=7pnhj6"
3131
title="RTK Query Video course at Egghead: Course Introduction and Application Walk through for RTK Query Basics"
32-
frameborder="0"
32+
frameborder="0"
3333
allowfullscreen
3434
style={{position:"absolute",top:0,left:0,width:"100%",height:"100%"}}
3535
></iframe>
@@ -287,7 +287,8 @@ import { Spinner } from '@/components/Spinner'
287287
import { TimeAgo } from '@/components/TimeAgo'
288288

289289
// highlight-next-line
290-
import { useGetPostsQuery, Post } from '@/features/api/apiSlice'
290+
import type { Post } from '@/features/api/apiSlice'
291+
import { useGetPostsQuery } from '@/features/api/apiSlice'
291292

292293
import { PostAuthor } from './PostAuthor'
293294
import { ReactionButtons } from './ReactionButtons'
@@ -479,7 +480,7 @@ export const SinglePostPage = () => {
479480
const currentUsername = useAppSelector(selectCurrentUsername)
480481
// highlight-next-line
481482
const { data: post, isFetching, isSuccess } = useGetPostQuery(postId!)
482-
483+
483484
// highlight-next-line
484485
let content: React.ReactNode
485486

@@ -508,7 +509,7 @@ export const SinglePostPage = () => {
508509
</article>
509510
)
510511
}
511-
512+
512513
// highlight-next-line
513514
return <section>{content}</section>
514515
}
@@ -729,7 +730,8 @@ Instead, we could make the existing list of posts partially transparent to indic
729730
// highlight-next-line
730731
import classnames from 'classnames'
731732

732-
import { useGetPostsQuery, Post } from '@/features/api/apiSlice'
733+
import type { Post } from '@/features/api/apiSlice'
734+
import { useGetPostsQuery } from '@/features/api/apiSlice'
733735

734736
// omit other imports and PostExcerpt
735737

docs/tutorials/essentials/part-8-rtk-query-advanced.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export const EditPostForm = () => {
119119

120120
// highlight-start
121121
const onSavePostClicked = async (
122-
// highlight-end
122+
// highlight-end
123123
e: React.FormEvent<EditPostFormElements>
124124
) => {
125125
// Prevent server submission
@@ -260,11 +260,16 @@ Fortunately, this is simple to fix. RTK Query actually uses `createAsyncThunk` i
260260
Currently, the toast listener is watching for the single specific action type with `actionCreator: addNewPost.fulfilled`. We'll update it to watch for the posts being added with `matcher: apiSlice.endpoints.addNewPost.matchFulfilled`:
261261

262262
```ts title="features/posts/postsSlice.ts"
263-
import { createEntityAdapter, createSelector, createSlice, EntityState, PayloadAction } from '@reduxjs/toolkit'
263+
import type { EntityState, PayloadAction } from '@reduxjs/toolkit'
264+
import {
265+
createEntityAdapter,
266+
createSelector,
267+
createSlice
268+
} from '@reduxjs/toolkit'
264269
import { client } from '@/api/client'
265270

266271
import type { RootState } from '@/app/store'
267-
import { AppStartListening } from '@/app/listenerMiddleware'
272+
import type { AppStartListening } from '@/app/listenerMiddleware'
268273
import { createAppAsyncThunk } from '@/app/withTypes'
269274

270275
// highlight-next-line
@@ -277,7 +282,9 @@ export const addPostsListeners = (startAppListening: AppStartListening) => {
277282
startAppListening({
278283
// highlight-next-line
279284
matcher: apiSlice.endpoints.addNewPost.matchFulfilled,
280-
effect: async (action, listenerApi) => {
285+
effect: async (action, listenerApi) => {}
286+
})
287+
}
281288
```
282289

283290
Now the toast should show correctly again when we add a post.
@@ -660,7 +667,8 @@ import type { TypedUseQueryStateResult } from '@reduxjs/toolkit/query/react'
660667
import { useAppSelector } from '@/app/hooks'
661668

662669
// highlight-next-line
663-
import { useGetPostsQuery, Post } from '@/features/api/apiSlice'
670+
import type { Post } from '@/features/api/apiSlice'
671+
import { useGetPostsQuery } from '@/features/api/apiSlice'
664672

665673
import { selectUserById } from './usersSlice'
666674

@@ -951,7 +959,7 @@ Similar to `onQueryStarted`, `onCacheEntryAdded` receives two parameters. The fi
951959
There's also two additional Promises that can be waited on:
952960

953961
- `cacheDataLoaded`: resolves with the first cached value received, and is typically used to wait for an actual value to be in the cache before doing more logic
954-
- `cacheEntryRemoved `: resolves when this cache entry is removed (i.e, there are no more subscribers and the cache entry has been garbage-collected)
962+
- `cacheEntryRemoved`: resolves when this cache entry is removed (i.e, there are no more subscribers and the cache entry has been garbage-collected)
955963

956964
As long as 1+ subscribers for the data are still active, the cache entry is kept alive. When the number of subscribers goes to 0 and the cache lifetime timer expires, the cache entry will be removed, and `cacheEntryRemoved` will resolve. Typically, the usage pattern is:
957965

@@ -1397,7 +1405,6 @@ const notificationsSlice = createSlice({
13971405
}
13981406
},
13991407
})
1400-
14011408
```
14021409
14031410
When the cache entry is added, we create a new `WebSocket` instance that will connect to the mock server backend.

docs/tutorials/typescript.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ All generated actions should be defined using the `PayloadAction<T>` type from R
9292
You can safely import the `RootState` type from the store file here. It's a circular import, but the TypeScript compiler can correctly handle that for types. This may be needed for use cases like writing selector functions.
9393

9494
```ts title="features/counter/counterSlice.ts"
95-
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
95+
import type { PayloadAction } from '@reduxjs/toolkit'
96+
import { createSlice } from '@reduxjs/toolkit'
9697
import type { RootState } from '../../app/store'
9798

9899
// highlight-start

0 commit comments

Comments
 (0)