install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/redux-typescript-patterns" ~/.claude/skills/intense-visions-harness-engineering-redux-typescript-patterns && rm -rf "$T"
manifest:
agents/skills/claude-code/redux-typescript-patterns/SKILL.mdsource content
Redux TypeScript Patterns
Type Redux state, actions, thunks, and hooks with full inference and minimal manual annotation
When to Use
- Setting up TypeScript types for a Redux Toolkit project
- Fixing type errors in slices, thunks, or connected components
- Adding type safety to
anduseDispatchuseSelector - Typing
,extraReducers
, or middlewarecreateAsyncThunk
Instructions
- Infer
andRootState
from the store — never define them manually.AppDispatch - Create typed hooks once (
,useAppDispatch
) and use them everywhere.useAppSelector - Use
for reducer parameter types. RTK infers the rest fromPayloadAction<T>
.createSlice - Type
with three generic arguments:createAsyncThunk
.<ReturnType, ArgType, ThunkApiConfig> - In
, use the builder callback — it provides full type inference for each case.extraReducers - Use
type guard for narrowing rejection payloads.isRejectedWithValue - Avoid
type assertions in reducers — if you need them, the type definition is wrong.as
// store/index.ts — inferred types export type RootState = ReturnType<typeof store.getState>; export type AppDispatch = typeof store.dispatch; // Typed hooks — use throughout the app export const useAppDispatch: () => AppDispatch = useDispatch; export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
// Typed createAsyncThunk interface FetchError { message: string; code: number; } export const fetchUser = createAsyncThunk< User, // Fulfilled return type string, // Argument type (userId) { state: RootState; rejectValue: FetchError } // ThunkAPI config >( 'users/fetch', async (userId, { rejectWithValue }) => { const res = await fetch(`/api/users/${userId}`); if (!res.ok) { return rejectWithValue({ message: 'Not found', code: res.status }); } return res.json(); } ); // extraReducers with full inference extraReducers: (builder) => { builder .addCase(fetchUser.fulfilled, (state, action) => { // action.payload is User (inferred) state.currentUser = action.payload; }) .addCase(fetchUser.rejected, (state, action) => { if (action.payload) { // action.payload is FetchError (from rejectWithValue) state.error = action.payload.message; } else { // action.error is SerializedError (thrown exception) state.error = action.error.message ?? 'Unknown error'; } }); },
Details
ThunkAPI config object: Pass
{ state: RootState; rejectValue: T; dispatch: AppDispatch } as the third generic to createAsyncThunk. This types getState(), rejectWithValue(), and dispatch() inside the payload creator.
Middleware typing: Custom middleware receives
MiddlewareAPI<AppDispatch, RootState>:
const logger: Middleware<{}, RootState> = (storeApi) => (next) => (action) => { console.log('dispatching', action); return next(action); };
Entity adapter typing: Pass the entity type to
createEntityAdapter<User>(). The adapter methods and selectors are fully typed from this.
Common type errors and fixes:
inProperty does not exist on type
— addgetState()
to the thunk configstate: RootState
— check that the action creator's prepare callback return type matchesArgument not assignable to PayloadAction
— usually from circular slice imports; break the cycle with a shared types fileType instantiation is excessively deep
— import types withCannot use namespace as type
to avoid circular dependenciesimport type
RTK 2.0 changes:
Tuple replaces arrays for middleware. combineSlices provides automatic type inference for lazy-loaded slices. The reducer field in configureStore accepts a combineSlices result directly.
Source
https://redux-toolkit.js.org/usage/usage-with-typescript
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.