I'm trying to customize the Redux Toolkit`s included Middleware to add an extra argument. This extra argument is an implementation of a Repository.
When I configure the store I add that extra argument:
export const store = configureStore({
reducer: {
students: students,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: {
extraArgument: createAPIStudentRepository,
},
serializableCheck: false,
}),
});
createAPIStudentRepository
is of type StudentRepository
:
export const createAPIStudentRepository = (): StudentRepository => {
return {
loadStudents: async (query: string, page: number, limit: number) => {
const response = await fetch(API_STUDENTS_URL(query, page, limit));
const results = (await response.json()) as Student[];
return results;
},
};
};
And here is the Student
repository:
export interface StudentRepository {
loadAStudents(
query: string,
page: number,
limit: number
): Promise<Student[]>;
}
Then, in my Redux Thunk I want to use the createAPIStudentRepository
that I injected when configuring the store:
interface StudentParams {
query?: string;
page?: number;
limit?: number;
}
export const fetchStudents = createAsyncThunk(
'student/fetch',
async (
params: StudentParams,
{ fulfillWithValue, rejectWithValue, extra }
) => {
const { query = '', page = 1, limit = 10 } = params;
try {
//TODO: here is the problem, extra() throws an error: "extra" is of type
//"unknown"
const studentRepository = extra();
const results = await studentRepository.loadAStudents(
query,
page,
limit
);
return { results, page, query };
} catch (error: unknown) {
console.log(error);
return rejectWithValue("Error: couldn't fetch Students");
}
}
);
The issue is in the TODO
line. This code works but I get a Typescript
error: "extra" is of type "unknwon"
.
Any ideas of how I can let Typescript
know the type?
Reference:
You can explicitly type the createAsyncThunk
function. See Usage with Typescript: createAsyncThunk for details.
interface StudentParams {
query?: string;
page?: number;
limit?: number;
}
export const fetchStudents = createAsyncThunk<
// Return type
{ results: Student[], page: number, query: string },
// Argument
StudentParams,
// ThunkApi
{
extra: () => StudentRepository
}
>(
'student/fetch',
async (
params: StudentParams,
{ fulfillWithValue, rejectWithValue, extra }
) => {
const { query = '', page = 1, limit = 10 } = params;
try {
const studentRepository = extra();
const results = await studentRepository.loadAStudents(
query,
page,
limit
);
return { results, page, query };
} catch (error: unknown) {
console.log(error);
return rejectWithValue("Error: couldn't fetch Students");
}
}
);
Or you can cast the extra
type. I believe the following should work.
interface StudentParams {
query?: string;
page?: number;
limit?: number;
}
export const fetchStudents = createAsyncThunk(
'student/fetch',
async (
params: StudentParams,
{ fulfillWithValue, rejectWithValue, extra }
) => {
const { query = '', page = 1, limit = 10 } = params;
try {
const studentRepository = (extra as () => StudentRepository)();
const results = await studentRepository.loadAStudents(
query,
page,
limit
);
return { results, page, query };
} catch (error: unknown) {
console.log(error);
return rejectWithValue("Error: couldn't fetch Students");
}
}
);