Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript: createStore preloadedState parameter should be Partial<S> when using combineReducers #2552

Closed
dawnmist opened this issue Aug 13, 2017 · 5 comments

Comments

@dawnmist
Copy link

Do you want to request a feature or report a bug?
Minor Bug in typescript definitions

What is the current behavior?
When using typescript and combineReducers, the preloadedState parameter is forced to contain the full/entire initial state for every reducer. This is because the typescript definition for the preloadedState parameter is "S" instead of "Partial<S>".

What is the expected behavior?
From the redux documentation: http://redux.js.org/docs/recipes/reducers/InitializingState.html

With combineReducers() the behavior is more nuanced. Those reducers whose state is specified in preloadedState will receive that state. Other reducers will receive undefined and because of that will fall back to the state = ... default argument they specify.

In general, preloadedState wins over the state specified by the reducer. This lets reducers specify initial data that makes sense to them as default arguments, but also allows loading existing data (fully or partially) when you're hydrating the store from some persistent storage or the server.

The current typescript definition does not allow supplying state for only some reducers.

Which versions of Redux, and which browser and OS are affected by this issue? Did this work in previous versions of Redux?
All versions using typescript and the preloadedState parameter to createStore as far as I can see.

@aikoven
Copy link
Collaborator

aikoven commented Sep 13, 2017

You are right, moreover, it should be deeply partial, i.e. partial on any depth level.

Something like

type DeepPartial<T> = {
  [K in keyof T]?: DeepPartial<T[K]>
}

@timdorr
Copy link
Member

timdorr commented Oct 23, 2017

Dumb TS person question: Does the revamped typing solve this?
https://github.com/reactjs/redux/blob/next/index.d.ts

@dawnmist
Copy link
Author

dawnmist commented Oct 23, 2017

No. It still requires the complete state for the preloaded state.

I've been using a local package override to add a partial store version based on the comments here, which does work - I just wasn't sure if it was valid for a reducer that produced an object with a few fields, as it would also be marked as partial and therefore permitted to become only half set.

For example, a reducer that produced "{ pageNum: number; numPerPage: number;}" as its output could be preloaded as only containing one of the two fields, and making it deeply partial would not pick up the error. I went through my reducers to split out anything like that into separate reducers so that I wouldn't run into that problem, but I hadn't yet worked out a way to fix it properly to be able to send a patch.

What I've been using:

import * as Redux from 'redux';

export type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> };

declare module 'redux' {
  export interface StoreCreator {
    <S>(reducer: Reducer<S>, preloadedState: DeepPartial<S>, enhancer?: StoreEnhancer<S>): Store<S>;
  }
}

It really needs to be deeply partial only on the reducer levels, but not within a final store object produced by a single sub-reducer, so that a reducer may or may not be included in the store - but if it is included it must be fully included. I do not know how to identify the difference between a combineReducers output and a final output object to be able to mark the combineReducers ones as Partial but the final ones as full.

Looking at the new version, I'll need to update that to add the A and N parameters - but they do not change the preloadedState requiring the entire state in the next redux defintions.

@aikoven
Copy link
Collaborator

aikoven commented Oct 24, 2017

See #2679

@OliverJAsh
Copy link
Contributor

It really needs to be deeply partial only on the reducer levels, but not within a final store object produced by a single sub-reducer, so that a reducer may or may not be included in the store - but if it is included it must be fully included. I do not know how to identify the difference between a combineReducers output and a final output object to be able to mark the combineReducers ones as Partial but the final ones as full.

I opened an issue to track this: #2808

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants