When it comes to Redux, there are various types to take note of:
declare const $CombinedState: unique symbol
/**
* The base state type for reducers that are created with `combineReducers()`.
*
* This particular type helps the `createStore()` method in inferring which levels of the
* preloaded state can be partial.
*
* Due to TypeScript being very duck-typed, a type needs to possess some form of
* identifying property to differentiate it from other types with similar
* prototypes for type checking purposes. This is why this type includes the
* `$CombinedState` symbol property. Without this property, the type would essentially
* match any object. Despite the fact that the symbol may not physically exist because it's an internal
* (i.e. not exported), and its value is never checked internally. As it's a
* symbol property, it's not meant to be enumerable, and the value is
* always typed as undefined, so it should never hold any meaningful
* value anyway. It just serves the purpose of distinguishing this type from a plain `{}`.
*/
export type CombinedState<S> = { readonly [$CombinedState]?: undefined } & S
I find myself slightly puzzled regarding the use of this symbol and type.
One example where you might encounter it is in combineReducers
export default function combineReducers<S>(
reducers: ReducersMapObject<S, any>
): Reducer<CombinedState<S>>
export default function combineReducers<S, A extends Action = AnyAction>(
reducers: ReducersMapObject<S, A>
): Reducer<CombinedState<S>, A>
export default function combineReducers<M extends ReducersMapObject<any, any>>(
reducers: M
): Reducer<
CombinedState<StateFromReducersMapObject<M>>,
ActionFromReducersMapObject<M>
>
export default function combineReducers(reducers: ReducersMapObject) {
const reducerKeys = Object.keys(reducers)
const finalReducers: ReducersMapObject = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning(`No reducer provided for key "${key}"`)
}
}
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
The comments suggest that its purpose is to distinguish it from {}
or an empty type, yet there doesn't seem to be any part where it actually checks for this type. Additionally, the comments mention that internally the value is never checked, so why include it at all apart from potentially causing confusion for individuals like me?