Episode ini melengkapi project Redux dengan TypeScript: mendefinisikan RootState dan AppDispatch dari store, membuat typed hooks useAppSelector dan useAppDispatch, memberi generic pada createAsyncThunk, serta memakai createSelector dengan type inference penuh.

Sejauh ini kita menulis TypeScript tanpa banyak memanfaatkan type safety-nya. Episode 7 membenahi itu: kalian akan memahami bagaimana meng-typing store agar TypeScript ikut menjaga kode kalian — mencegah typo nama state, memastikan action yang di-dispatch valid, dan memberikan autocomplete di editor.
Typing yang benar bukan formalitas. Di tim besar, type error yang tertangkap saat compile menghemat jam kerja debugging. Dan karena Redux Toolkit dibangun TypeScript-first, dukungan typenya sudah lengkap sejak awal.
Cara paling mudah mendefinisikan tipe adalah menurunkannya langsung dari store:
import { configureStore } from "@reduxjs/toolkit"
import counterReducer from "../features/counter/counterSlice"
export const store = configureStore({
reducer: {
counter: counterReducer,
},
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatchReturnType<typeof store.getState> secara otomatis menangkap bentuk seluruh state. Saat slice baru ditambahkan, RootState ikut berubah — tidak perlu diperbarui manual.
RootState dipakai sebagai tipe argumen selector.AppDispatch dipakai sebagai tipe argumen dispatch.Kedua tipe inilah yang membuat useSelector dan useDispatch menjadi type-safe.
Daripada menulis useSelector((state: RootState) => ...) di setiap komponen, buat versi typed sekali saja:
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
import type { RootState, AppDispatch } from "./store"
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelectoruseAppSelector dan useAppDispatch sekarang tahu bentuk state dan dispatch aplikasi kalian. Dari sini, seluruh komponen memakai hooks ber-typing ini — bukan langsung dari react-redux.
const count = useAppSelector((state) => state.counter.count)
const dispatch = useAppDispatch()Dengan useAppSelector, parameter selector otomatis bertipe RootState — editor akan memberi tahu jika kalian mengetik nama field yang salah. Konsisten memakai typed hooks adalah kebiasaan yang disarankan resmi oleh dokumentasi Redux.
createAsyncThunk menerima tiga generic: tipe hasil, tipe argumen, dan tipe thunk config:
import { createAsyncThunk } from "@reduxjs/toolkit"
import type { RootState } from "../../app/store"
interface Post {
id: number
title: string
}
export const fetchPosts = createAsyncThunk<
Post[],
void,
{ state: RootState }
>("posts/fetchPosts", async (_, { getState }) => {
const res = await fetch("/api/posts")
const data: Post[] = await res.json()
return data
})createAsyncThunk<Post[], void, { state: RootState }> berarti: hasil yang di-return bertipe Post[], thunk tidak menerima argumen (void), dan getState bertipe RootState. state: RootState memungkinkan membaca state lain di dalam payloadCreator.
Dengan generic { state: RootState }, kalian bisa membaca state saat menulis thunk:
export const fetchPosts = createAsyncThunk<Post[], void, { state: RootState }>(
"posts/fetchPosts",
async (_, { getState }) => {
const { auth } = getState()
const res = await fetch("/api/posts", {
headers: { Authorization: `Bearer ${auth.token}` },
})
return res.json()
},
)getState() sekarang mengembalikan RootState yang ter-typing, sehingga auth.token terautentikasi oleh TypeScript.
Untuk selector yang melakukan komputasi ulang mahal, gunakan createSelector dengan inference otomatis:
import { createSelector } from "@reduxjs/toolkit"
const selectItems = (state: RootState) => state.posts.items
const selectFilter = (state: RootState) => state.posts.filter
export const selectVisiblePosts = createSelector(
[selectItems, selectFilter],
(items, filter) => items.filter((p) => p.title.includes(filter)),
)createSelector menurunkan tipe hasil dari argumen selector-nya, sehingga selectVisiblePosts langsung ter-typing tanpa deklarasi manual. Detail memoization dan performanya kita bahas di episode 13.
Episode 7 melengkapi proyek kalian dengan TypeScript yang benar: tipe diturunkan dari store, hooks di-typing sekali dan dipakai di mana-mana, thunk diberi generic, dan selector memanfaatkan inference.
Inti yang harus dibawa pulang:
RootState dan AppDispatch diturunkan dari store dengan ReturnType dan typeof.useAppSelector dan useAppDispatch sekali di app/hooks.ts.createAsyncThunk<Result, Arg, { state: RootState }> untuk thunk yang ter-typing.getState() dalam thunk mengembalikan RootState bila generic dipasang.createSelector menurunkan tipe hasil secara otomatis.Di episode 8 selanjutnya kita masuk dunia RTK Query — createApi dengan fetchBaseQuery, mendefinisikan endpoints query, memakai useGetPostsQuery di komponen, dan memahami caching otomatis plus deduplication request yang menghemat jaringan.