1

I tried to ask this earlier generically (Why can't I assign a U to a Partial<T> when T extends U?) and I think I now understand why S extends {dirty: boolean} is incorrect (S could be {dirty: false}, but most of the suggestions were to rewrite the function in some way. So, how do I rewrite this function so that it has proper type checking and doesn't require a cast?

import {ActionCreatorWithPreparedPayload} from '@reduxjs/toolkit';
import {assert, pick} from '@helpmedo/util';
import {State, ThunkAction} from '@helpmedo/state';

export const createAsyncUpdateAction = <Arg, S extends {dirty: boolean}, P>(
  updateAction: ActionCreatorWithPreparedPayload<[Arg, Partial<S>], P>,
  selector: (state: State, arg: Arg) => S,
) => (
  arg: Arg,
  update: Partial<S>,
  asyncUpdate: () => Promise<unknown>,
): ThunkAction<unknown> => async (dispatch, getState) => {
  const state = selector(getState(), arg);
  assert(!state.dirty, 'Attempt to modify dirty state');
  const save = pick(state, Object.keys(update));
  dispatch(updateAction(arg, {...update, dirty: true}));
  try {
    const result = await asyncUpdate();
    dispatch(updateAction(arg, {dirty: false} /* as Partial<S> */));
    return result;
  } catch (err) {
    dispatch(updateAction(arg, {...save, dirty: false}));
    throw err;
  }
};

The existing error is Argument of type '{ dirty: false; }' is not assignable to parameter of type 'Partial<S>'.ts(2345) on the line with the commented out cast.

btmorex
  • 476
  • 5
  • 16

2 Answers2

0

When you declare S extends { dirty: boolean } you are doing exactly what you're asking for in the question – you're declaring a type S which must have a dirty property.

When you declare a type as Partial<S>, you're saying that all the properties of S are optional. Therefore even the dirty property is.

Just getting rid of the partiality of S in updateAction like updateAction: ActionCreatorWithPreparedPayload<[Arg, S], P> and that should solve your problems

0

you are doing S extends { dirty: boolean } correctly. just replace Partial<S> with S should fix as SquattingSlavInTracksuit explained.