Skip to content

Commit b2fa380

Browse files
committed
Add Id type parameter to createEntityAdapter
1 parent 44b4f67 commit b2fa380

27 files changed

+330
-203
lines changed

packages/rtk-query-codegen-openapi/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,5 @@ yalc.lock
137137
lib
138138
yarn.lock
139139
test/tmp/example.ts
140+
test/tmp/emptyApi.ts
141+
test/tmp/out.ts

packages/toolkit/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ Redux Toolkit includes these APIs:
6060
- `configureStore()`: wraps `createStore` to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, add whatever Redux middleware you supply, includes `redux-thunk` by default, and enables use of the Redux DevTools Extension.
6161
- `createReducer()`: lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the [`immer` library](https://github.com/mweststrate/immer) to let you write simpler immutable updates with normal mutative code, like `state.todos[3].completed = true`.
6262
- `createAction()`: generates an action creator function for the given action type string. The function itself has `toString()` defined, so that it can be used in place of the type constant.
63-
- `createSlice()`: combines `createReducer()` + `createAction()`. Accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
64-
- `createListenerMiddleware()`: lets you define "listener" entries that contain an "effect" callback with additional logic, and a way to specify when that callback should run based on dispatched actions or state changes. A lightweight alternative to Redux async middleware like sagas and observables.
63+
- `createSlice()`: combines `createReducer()` + `createAction()`. Accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
64+
- `createListenerMiddleware()`: lets you define "listener" entries that contain an "effect" callback with additional logic, and a way to specify when that callback should run based on dispatched actions or state changes. A lightweight alternative to Redux async middleware like sagas and observables.
6565
- `createAsyncThunk()`: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches `pending/resolved/rejected` action types based on that promise
6666
- `createEntityAdapter()`: generates a set of reusable reducers and selectors to manage normalized data in the store
6767
- The `createSelector()` utility from the [Reselect](https://github.com/reduxjs/reselect) library, re-exported for ease of use.

packages/toolkit/src/entities/create_adapter.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,27 @@ import type {
33
Comparer,
44
IdSelector,
55
EntityAdapter,
6+
EntityId,
67
} from './models'
78
import { createInitialStateFactory } from './entity_state'
89
import { createSelectorsFactory } from './state_selectors'
910
import { createSortedStateAdapter } from './sorted_state_adapter'
1011
import { createUnsortedStateAdapter } from './unsorted_state_adapter'
1112

13+
export interface EntityAdapterOptions<T, Id extends EntityId> {
14+
selectId?: IdSelector<T, Id>
15+
sortComparer?: false | Comparer<T>
16+
}
17+
18+
export function createEntityAdapter<T, Id extends EntityId>(options: {
19+
selectId: IdSelector<T, Id>
20+
sortComparer?: false | Comparer<T>
21+
}): EntityAdapter<T, Id>
22+
23+
export function createEntityAdapter<T extends { id: EntityId }>(options?: {
24+
sortComparer?: false | Comparer<T>
25+
}): EntityAdapter<T, T['id']>
26+
1227
/**
1328
*
1429
* @param options
@@ -17,18 +32,18 @@ import { createUnsortedStateAdapter } from './unsorted_state_adapter'
1732
*/
1833
export function createEntityAdapter<T>(
1934
options: {
20-
selectId?: IdSelector<T>
35+
selectId?: IdSelector<T, EntityId>
2136
sortComparer?: false | Comparer<T>
2237
} = {}
23-
): EntityAdapter<T> {
24-
const { selectId, sortComparer }: EntityDefinition<T> = {
38+
): EntityAdapter<T, EntityId> {
39+
const { selectId, sortComparer }: EntityDefinition<T, EntityId> = {
2540
sortComparer: false,
2641
selectId: (instance: any) => instance.id,
2742
...options,
2843
}
2944

30-
const stateFactory = createInitialStateFactory<T>()
31-
const selectorsFactory = createSelectorsFactory<T>()
45+
const stateFactory = createInitialStateFactory<T, EntityId>()
46+
const selectorsFactory = createSelectorsFactory<T, EntityId>()
3247
const stateAdapter = sortComparer
3348
? createSortedStateAdapter(selectId, sortComparer)
3449
: createUnsortedStateAdapter(selectId)

packages/toolkit/src/entities/entity_state.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
import type { EntityState } from './models'
1+
import type { EntityId, EntityState } from './models'
22

3-
export function getInitialEntityState<V>(): EntityState<V> {
3+
export function getInitialEntityState<T, Id extends EntityId>(): EntityState<
4+
T,
5+
Id
6+
> {
47
return {
58
ids: [],
69
entities: {},
710
}
811
}
912

10-
export function createInitialStateFactory<V>() {
11-
function getInitialState(): EntityState<V>
13+
export function createInitialStateFactory<T, Id extends EntityId>() {
14+
function getInitialState(): EntityState<T, Id>
1215
function getInitialState<S extends object>(
1316
additionalState: S
14-
): EntityState<V> & S
17+
): EntityState<T, Id> & S
1518
function getInitialState(additionalState: any = {}): any {
1619
return Object.assign(getInitialEntityState(), additionalState)
1720
}

packages/toolkit/src/entities/models.ts

Lines changed: 94 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -14,158 +14,166 @@ export type Comparer<T> = (a: T, b: T) => number
1414
/**
1515
* @public
1616
*/
17-
export type IdSelector<T> = (model: T) => EntityId
17+
export type IdSelector<T, Id extends EntityId> = (model: T) => Id
1818

1919
/**
2020
* @public
2121
*/
22-
export interface DictionaryNum<T> {
23-
[id: number]: T | undefined
24-
}
25-
26-
/**
27-
* @public
28-
*/
29-
export interface Dictionary<T> extends DictionaryNum<T> {
30-
[id: string]: T | undefined
31-
}
22+
export type Dictionary<T, Id extends EntityId> = Partial<Record<Id, T>>
3223

3324
/**
3425
* @public
3526
*/
36-
export type Update<T> = { id: EntityId; changes: Partial<T> }
27+
export type Update<T, Id extends EntityId> = { id: Id; changes: Partial<T> }
3728

3829
/**
3930
* @public
4031
*/
41-
export interface EntityState<T> {
42-
ids: EntityId[]
43-
entities: Dictionary<T>
32+
export interface EntityState<T, Id extends EntityId> {
33+
ids: Id[]
34+
entities: Dictionary<T, Id>
4435
}
4536

4637
/**
4738
* @public
4839
*/
49-
export interface EntityDefinition<T> {
50-
selectId: IdSelector<T>
40+
export interface EntityDefinition<T, Id extends EntityId> {
41+
selectId: IdSelector<T, Id>
5142
sortComparer: false | Comparer<T>
5243
}
5344

54-
export type PreventAny<S, T> = IsAny<S, EntityState<T>, S>
45+
export type PreventAny<S, T, Id extends EntityId> = IsAny<
46+
S,
47+
EntityState<T, Id>,
48+
S
49+
>
5550

5651
/**
5752
* @public
5853
*/
59-
export interface EntityStateAdapter<T> {
60-
addOne<S extends EntityState<T>>(state: PreventAny<S, T>, entity: T): S
61-
addOne<S extends EntityState<T>>(
62-
state: PreventAny<S, T>,
54+
export interface EntityStateAdapter<T, Id extends EntityId> {
55+
addOne<S extends EntityState<T, Id>>(
56+
state: PreventAny<S, T, Id>,
57+
entity: T
58+
): S
59+
addOne<S extends EntityState<T, Id>>(
60+
state: PreventAny<S, T, Id>,
6361
action: PayloadAction<T>
6462
): S
6563

66-
addMany<S extends EntityState<T>>(
67-
state: PreventAny<S, T>,
68-
entities: readonly T[] | Record<EntityId, T>
64+
addMany<S extends EntityState<T, Id>>(
65+
state: PreventAny<S, T, Id>,
66+
entities: readonly T[] | Record<Id, T>
6967
): S
70-
addMany<S extends EntityState<T>>(
71-
state: PreventAny<S, T>,
72-
entities: PayloadAction<readonly T[] | Record<EntityId, T>>
68+
addMany<S extends EntityState<T, Id>>(
69+
state: PreventAny<S, T, Id>,
70+
entities: PayloadAction<readonly T[] | Record<Id, T>>
7371
): S
7472

75-
setOne<S extends EntityState<T>>(state: PreventAny<S, T>, entity: T): S
76-
setOne<S extends EntityState<T>>(
77-
state: PreventAny<S, T>,
73+
setOne<S extends EntityState<T, Id>>(
74+
state: PreventAny<S, T, Id>,
75+
entity: T
76+
): S
77+
setOne<S extends EntityState<T, Id>>(
78+
state: PreventAny<S, T, Id>,
7879
action: PayloadAction<T>
7980
): S
80-
setMany<S extends EntityState<T>>(
81-
state: PreventAny<S, T>,
82-
entities: readonly T[] | Record<EntityId, T>
81+
setMany<S extends EntityState<T, Id>>(
82+
state: PreventAny<S, T, Id>,
83+
entities: readonly T[] | Record<Id, T>
8384
): S
84-
setMany<S extends EntityState<T>>(
85-
state: PreventAny<S, T>,
86-
entities: PayloadAction<readonly T[] | Record<EntityId, T>>
85+
setMany<S extends EntityState<T, Id>>(
86+
state: PreventAny<S, T, Id>,
87+
entities: PayloadAction<readonly T[] | Record<Id, T>>
8788
): S
88-
setAll<S extends EntityState<T>>(
89-
state: PreventAny<S, T>,
90-
entities: readonly T[] | Record<EntityId, T>
89+
setAll<S extends EntityState<T, Id>>(
90+
state: PreventAny<S, T, Id>,
91+
entities: readonly T[] | Record<Id, T>
9192
): S
92-
setAll<S extends EntityState<T>>(
93-
state: PreventAny<S, T>,
94-
entities: PayloadAction<readonly T[] | Record<EntityId, T>>
93+
setAll<S extends EntityState<T, Id>>(
94+
state: PreventAny<S, T, Id>,
95+
entities: PayloadAction<readonly T[] | Record<Id, T>>
9596
): S
9697

97-
removeOne<S extends EntityState<T>>(state: PreventAny<S, T>, key: EntityId): S
98-
removeOne<S extends EntityState<T>>(
99-
state: PreventAny<S, T>,
100-
key: PayloadAction<EntityId>
98+
removeOne<S extends EntityState<T, Id>>(
99+
state: PreventAny<S, T, Id>,
100+
key: Id
101+
): S
102+
removeOne<S extends EntityState<T, Id>>(
103+
state: PreventAny<S, T, Id>,
104+
key: PayloadAction<Id>
101105
): S
102106

103-
removeMany<S extends EntityState<T>>(
104-
state: PreventAny<S, T>,
105-
keys: readonly EntityId[]
107+
removeMany<S extends EntityState<T, Id>>(
108+
state: PreventAny<S, T, Id>,
109+
keys: readonly Id[]
106110
): S
107-
removeMany<S extends EntityState<T>>(
108-
state: PreventAny<S, T>,
109-
keys: PayloadAction<readonly EntityId[]>
111+
removeMany<S extends EntityState<T, Id>>(
112+
state: PreventAny<S, T, Id>,
113+
keys: PayloadAction<readonly Id[]>
110114
): S
111115

112-
removeAll<S extends EntityState<T>>(state: PreventAny<S, T>): S
116+
removeAll<S extends EntityState<T, Id>>(state: PreventAny<S, T, Id>): S
113117

114-
updateOne<S extends EntityState<T>>(
115-
state: PreventAny<S, T>,
116-
update: Update<T>
118+
updateOne<S extends EntityState<T, Id>>(
119+
state: PreventAny<S, T, Id>,
120+
update: Update<T, Id>
117121
): S
118-
updateOne<S extends EntityState<T>>(
119-
state: PreventAny<S, T>,
120-
update: PayloadAction<Update<T>>
122+
updateOne<S extends EntityState<T, Id>>(
123+
state: PreventAny<S, T, Id>,
124+
update: PayloadAction<Update<T, Id>>
121125
): S
122126

123-
updateMany<S extends EntityState<T>>(
124-
state: PreventAny<S, T>,
125-
updates: ReadonlyArray<Update<T>>
127+
updateMany<S extends EntityState<T, Id>>(
128+
state: PreventAny<S, T, Id>,
129+
updates: ReadonlyArray<Update<T, Id>>
126130
): S
127-
updateMany<S extends EntityState<T>>(
128-
state: PreventAny<S, T>,
129-
updates: PayloadAction<ReadonlyArray<Update<T>>>
131+
updateMany<S extends EntityState<T, Id>>(
132+
state: PreventAny<S, T, Id>,
133+
updates: PayloadAction<ReadonlyArray<Update<T, Id>>>
130134
): S
131135

132-
upsertOne<S extends EntityState<T>>(state: PreventAny<S, T>, entity: T): S
133-
upsertOne<S extends EntityState<T>>(
134-
state: PreventAny<S, T>,
136+
upsertOne<S extends EntityState<T, Id>>(
137+
state: PreventAny<S, T, Id>,
138+
entity: T
139+
): S
140+
upsertOne<S extends EntityState<T, Id>>(
141+
state: PreventAny<S, T, Id>,
135142
entity: PayloadAction<T>
136143
): S
137144

138-
upsertMany<S extends EntityState<T>>(
139-
state: PreventAny<S, T>,
140-
entities: readonly T[] | Record<EntityId, T>
145+
upsertMany<S extends EntityState<T, Id>>(
146+
state: PreventAny<S, T, Id>,
147+
entities: readonly T[] | Record<Id, T>
141148
): S
142-
upsertMany<S extends EntityState<T>>(
143-
state: PreventAny<S, T>,
144-
entities: PayloadAction<readonly T[] | Record<EntityId, T>>
149+
upsertMany<S extends EntityState<T, Id>>(
150+
state: PreventAny<S, T, Id>,
151+
entities: PayloadAction<readonly T[] | Record<Id, T>>
145152
): S
146153
}
147154

148155
/**
149156
* @public
150157
*/
151-
export interface EntitySelectors<T, V> {
152-
selectIds: (state: V) => EntityId[]
153-
selectEntities: (state: V) => Dictionary<T>
158+
export interface EntitySelectors<T, V, Id extends EntityId> {
159+
selectIds: (state: V) => Id[]
160+
selectEntities: (state: V) => Dictionary<T, Id>
154161
selectAll: (state: V) => T[]
155162
selectTotal: (state: V) => number
156-
selectById: (state: V, id: EntityId) => T | undefined
163+
selectById: (state: V, id: Id) => T | undefined
157164
}
158165

159166
/**
160167
* @public
161168
*/
162-
export interface EntityAdapter<T> extends EntityStateAdapter<T> {
163-
selectId: IdSelector<T>
169+
export interface EntityAdapter<T, Id extends EntityId>
170+
extends EntityStateAdapter<T, Id> {
171+
selectId: IdSelector<T, Id>
164172
sortComparer: false | Comparer<T>
165-
getInitialState(): EntityState<T>
166-
getInitialState<S extends object>(state: S): EntityState<T> & S
167-
getSelectors(): EntitySelectors<T, EntityState<T>>
173+
getInitialState(): EntityState<T, Id>
174+
getInitialState<S extends object>(state: S): EntityState<T, Id> & S
175+
getSelectors(): EntitySelectors<T, EntityState<T, Id>, Id>
168176
getSelectors<V>(
169-
selectState: (state: V) => EntityState<T>
170-
): EntitySelectors<T, V>
177+
selectState: (state: V) => EntityState<T, Id>
178+
): EntitySelectors<T, V, Id>
171179
}

0 commit comments

Comments
 (0)