We are using the exact same technology stack and ran into the exact same issue. We decided on keeping the compile time checks and ~typesafety instead of keeping immutable. To ensure we still had immutable data structures we wrote a middleware that calls freeze on the store state after every action. This middleware is only configured in development builds. Then in the reducer, we first copy the state and then update the properties directly which keeps the typing intact. It takes more lines of code than using immutable but you get to keep all the nice refactoring capabilities of typescript.
We are using the exact same technology stack and ran into the exact same issue. We decided on keeping the compile time checks and ~typesafety instead of keeping immutable. To ensure we still had immutable data structures we wrote a middleware that calls freeze on the store state after every action. This middleware is only configured in development builds. Then in the reducer, we first copy the state and then update the properties directly which keeps the typing intact. It takes more lines of code than using immutable but you get to keep all the nice refactoring capabilities of typescript.