redux-toolkit
redux-toolkit copied to clipboard
Strange typescript behavior with fulfillWithValue
I'm having a little trouble understanding the typescript payload types from an async thunk. Given the following code:
export interface UserCompaniesState {
areUserCompaniesLoaded: boolean;
companies?: Array<PaidolUser>;
}
export const initialState: UserCompaniesState = {
areUserCompaniesLoaded: false,
companies: undefined,
};
export const getUserCompanies = createAsyncThunk(
'userCompanies/getUserCompanies',
async (user_id: string) => {
return (
API.graphql(
graphqlOperation(paidolUserByUserId, {
user_id,
})
) as Promise<GraphQLResult<PaidolUserByUserIdQuery>>
).then(
(response) =>
response.data?.paidolUserByUserId?.items.filter(isPaidolUser) || []
);
}
);
const userCompaniesSlice = createSlice({
name: 'userCompanies',
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(getUserCompanies.fulfilled, (state, action) => {
state.areUserCompaniesLoaded = true;
state.companies = action.payload;
});
},
});
export function isPaidolUser(
paidolUser: { __typename: 'PaidolUser' } | null
): paidolUser is PaidolUser {
return paidolUser !== null;
}
I get the following typescript error when I try to assign the thunk payload to state in my reducer:
Type 'PaidolUser[] | FulfillWithMeta<never, never>' is not assignable to type 'WritableDraft<PaidolUser>[] | undefined'.
Type 'FulfillWithMeta<never, never>' is missing the following properties from type 'WritableDraft<PaidolUser>[]': length, pop, push, concat, and 29 more.
I'm not sure what the FulfillWithMeta<never, never>
type is used for and I'm having a hard time googling for answers.
BUT! If I simply include { fulfillWithValue }
in my thunk args, even though I'm not calling that function everything works out OK:
export const getUserCompanies = createAsyncThunk(
'userCompanies/getUserCompanies',
async (user_id: string, { fulfillWithValue }) => {
return (
API.graphql(
graphqlOperation(paidolUserByUserId, {
user_id,
})
) as Promise<GraphQLResult<PaidolUserByUserIdQuery>>
).then(
(response) =>
response.data?.paidolUserByUserId?.items.filter(isPaidolUser) || []
);
}
);
In this case, action.payload
in my reducer is correctly typed as:
(parameter) action: PayloadAction<PaidolUser[], string, {
arg: string;
requestId: string;
requestStatus: "fulfilled";
}, never>
And I'm able to make the assignment state.companies = payload.action
without any extra type guarding.
Strangely, if I use fulfillWithValue()
to return my value from the thunk, then it's typed as unknown
in the action payload.
What is the FulfillWithMeta<never, never>
type used for, and should I be explicitly guarding against it in my reducer?
It works for me in this TypeScript Playground
Could you try to create a TypeScript playground where it is not working for you?
Have you checked that your tsconfig.json
has strict: true
?