Belajar Redux - TypeScript & Typing Store
Episode 7 of 23

Belajar Redux - TypeScript & Typing Store

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.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

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.

RootState dan AppDispatch

Cara paling mudah mendefinisikan tipe adalah menurunkannya langsung dari store:

JSapp/store.ts dengan typing
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.dispatch

ReturnType<typeof store.getState> secara otomatis menangkap bentuk seluruh state. Saat slice baru ditambahkan, RootState ikut berubah — tidak perlu diperbarui manual.

Kapan Tipe Ini Dipakai

  • RootState dipakai sebagai tipe argumen selector.
  • AppDispatch dipakai sebagai tipe argumen dispatch.

Kedua tipe inilah yang membuat useSelector dan useDispatch menjadi type-safe.

Typed Hooks: useAppSelector dan useAppDispatch

Membuat Hook Ber-typing

Daripada menulis useSelector((state: RootState) => ...) di setiap komponen, buat versi typed sekali saja:

JSapp/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
import type { RootState, AppDispatch } from "./store"
 
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

useAppSelector dan useAppDispatch sekarang tahu bentuk state dan dispatch aplikasi kalian. Dari sini, seluruh komponen memakai hooks ber-typing ini — bukan langsung dari react-redux.

Memakai Typed Hooks di Komponen

JSKomponen dengan typed hooks
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.

Typing Slice dan Thunk

Generic createAsyncThunk

createAsyncThunk menerima tiga generic: tipe hasil, tipe argumen, dan tipe thunk config:

JSThunk dengan generic lengkap
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.

Memakai State Lain di dalam Thunk

Dengan generic { state: RootState }, kalian bisa membaca state saat menulis thunk:

JSMembaca state di payloadCreator
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.

Typed Selectors dengan createSelector

Untuk selector yang melakukan komputasi ulang mahal, gunakan createSelector dengan inference otomatis:

JScreateSelector ber-typing
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.

Penutup

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.
  • Buat 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.
  • Konsisten memakai typed hooks adalah kebiasaan resmi yang disarankan.

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.