Skip to content

Commit fa2d899

Browse files
authored
Merge pull request #4638 from exuanbo/patch-1
fix(types/store): Unexpectedly narrowed return type of function `Store['getState']`
2 parents 105e389 + 9e8a320 commit fa2d899

File tree

3 files changed

+18
-10
lines changed

3 files changed

+18
-10
lines changed

src/createStore.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
StoreEnhancer,
66
Dispatch,
77
Observer,
8-
ListenerCallback
8+
ListenerCallback,
9+
UnknownIfNonSpecific
910
} from './types/store'
1011
import { Action } from './types/actions'
1112
import { Reducer } from './types/reducers'
@@ -46,7 +47,7 @@ export function createStore<
4647
>(
4748
reducer: Reducer<S, A>,
4849
enhancer?: StoreEnhancer<Ext, StateExt>
49-
): Store<S, A, StateExt> & Ext
50+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
5051
/**
5152
* @deprecated
5253
*
@@ -82,7 +83,7 @@ export function createStore<
8283
reducer: Reducer<S, A, PreloadedState>,
8384
preloadedState?: PreloadedState | undefined,
8485
enhancer?: StoreEnhancer<Ext, StateExt>
85-
): Store<S, A, StateExt> & Ext
86+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
8687
export function createStore<
8788
S,
8889
A extends Action,
@@ -93,7 +94,7 @@ export function createStore<
9394
reducer: Reducer<S, A, PreloadedState>,
9495
preloadedState?: PreloadedState | StoreEnhancer<Ext, StateExt> | undefined,
9596
enhancer?: StoreEnhancer<Ext, StateExt>
96-
): Store<S, A, StateExt> & Ext {
97+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext {
9798
if (typeof reducer !== 'function') {
9899
throw new Error(
99100
`Expected the root reducer to be a function. Instead, received: '${kindOf(
@@ -432,7 +433,7 @@ export function legacy_createStore<
432433
>(
433434
reducer: Reducer<S, A>,
434435
enhancer?: StoreEnhancer<Ext, StateExt>
435-
): Store<S, A, StateExt> & Ext
436+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
436437
/**
437438
* Creates a Redux store that holds the state tree.
438439
*
@@ -473,7 +474,7 @@ export function legacy_createStore<
473474
reducer: Reducer<S, A, PreloadedState>,
474475
preloadedState?: PreloadedState | undefined,
475476
enhancer?: StoreEnhancer<Ext, StateExt>
476-
): Store<S, A, StateExt> & Ext
477+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
477478
export function legacy_createStore<
478479
S,
479480
A extends Action,
@@ -484,6 +485,6 @@ export function legacy_createStore<
484485
reducer: Reducer<S, A>,
485486
preloadedState?: PreloadedState | StoreEnhancer<Ext, StateExt> | undefined,
486487
enhancer?: StoreEnhancer<Ext, StateExt>
487-
): Store<S, A, StateExt> & Ext {
488+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext {
488489
return createStore(reducer, preloadedState as any, enhancer)
489490
}

src/types/store.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export type Observer<T> = {
8181
export interface Store<
8282
S = any,
8383
A extends Action = UnknownAction,
84-
StateExt extends {} = {}
84+
StateExt extends unknown = unknown
8585
> {
8686
/**
8787
* Dispatches an action. It is the only way to trigger a state change.
@@ -164,6 +164,8 @@ export interface Store<
164164
[Symbol.observable](): Observable<S & StateExt>
165165
}
166166

167+
export type UnknownIfNonSpecific<T> = {} extends T ? unknown : T
168+
167169
/**
168170
* A store creator is a function that creates a Redux store. Like with
169171
* dispatching function, we must distinguish the base store creator,
@@ -180,7 +182,7 @@ export interface StoreCreator {
180182
<S, A extends Action, Ext extends {} = {}, StateExt extends {} = {}>(
181183
reducer: Reducer<S, A>,
182184
enhancer?: StoreEnhancer<Ext, StateExt>
183-
): Store<S, A, StateExt> & Ext
185+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
184186
<
185187
S,
186188
A extends Action,
@@ -191,7 +193,7 @@ export interface StoreCreator {
191193
reducer: Reducer<S, A, PreloadedState>,
192194
preloadedState?: PreloadedState | undefined,
193195
enhancer?: StoreEnhancer<Ext>
194-
): Store<S, A, StateExt> & Ext
196+
): Store<S, A, UnknownIfNonSpecific<StateExt>> & Ext
195197
}
196198

197199
/**

test/typescript/store.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ const funcWithStore = (store: Store<State, DerivedAction>) => {}
6161

6262
const store: Store<State> = createStore(reducer)
6363

64+
// test that nullable state is preserved
65+
const nullableStore = createStore((): string | null => null)
66+
67+
expectTypeOf(nullableStore.getState()).toEqualTypeOf<string | null>()
68+
6469
// ensure that an array-based state works
6570
const arrayReducer = (state: any[] = []) => state || []
6671
const storeWithArrayState: Store<any[]> = createStore(arrayReducer)

0 commit comments

Comments
 (0)