Skip to content

Commit a005d57

Browse files
authored
Merge pull request #3424 from EskiMojo14/entity-record
2 parents 2d22490 + 6a11af6 commit a005d57

11 files changed

+43
-41
lines changed

docs/api/createEntityAdapter.mdx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,19 +118,11 @@ export type Comparer<T> = (a: T, b: T) => number
118118

119119
export type IdSelector<T> = (model: T) => EntityId
120120

121-
export interface DictionaryNum<T> {
122-
[id: number]: T | undefined
123-
}
124-
125-
export interface Dictionary<T> extends DictionaryNum<T> {
126-
[id: string]: T | undefined
127-
}
128-
129121
export type Update<T> = { id: EntityId; changes: Partial<T> }
130122

131123
export interface EntityState<T> {
132124
ids: EntityId[]
133-
entities: Dictionary<T>
125+
entities: Record<EntityId, T>
134126
}
135127

136128
export interface EntityDefinition<T> {
@@ -183,7 +175,7 @@ export interface EntityStateAdapter<T> {
183175

184176
export interface EntitySelectors<T, V> {
185177
selectIds: (state: V) => EntityId[]
186-
selectEntities: (state: V) => Dictionary<T>
178+
selectEntities: (state: V) => Record<EntityId, T>
187179
selectAll: (state: V) => T[]
188180
selectTotal: (state: V) => number
189181
selectById: (state: V, id: EntityId) => T | undefined
@@ -228,7 +220,6 @@ All three options will insert _new_ entities into the list. However they differ
228220

229221
:::
230222

231-
232223
Each method has a signature that looks like:
233224

234225
```ts no-transpile
@@ -358,12 +349,8 @@ const booksSlice = createSlice({
358349
},
359350
})
360351

361-
const {
362-
bookAdded,
363-
booksLoading,
364-
booksReceived,
365-
bookUpdated,
366-
} = booksSlice.actions
352+
const { bookAdded, booksLoading, booksReceived, bookUpdated } =
353+
booksSlice.actions
367354

368355
const store = configureStore({
369356
reducer: {

packages/toolkit/src/entities/entity_state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function getInitialEntityState<T, Id extends EntityId>(): EntityState<
66
> {
77
return {
88
ids: [],
9-
entities: {},
9+
entities: {} as Record<Id, T>,
1010
}
1111
}
1212

packages/toolkit/src/entities/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export { createEntityAdapter } from './create_adapter'
22
export type {
3-
Dictionary,
43
EntityState,
54
EntityAdapter,
65
Update,

packages/toolkit/src/entities/models.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import type { UncheckedIndexedAccess } from '../uncheckedindexed'
12
import type { PayloadAction } from '../createAction'
2-
import type { IsAny } from '../tsHelpers'
3+
import type { CastAny, Id as Compute } from '../tsHelpers'
34

45
/**
56
* @public
@@ -16,11 +17,6 @@ export type Comparer<T> = (a: T, b: T) => number
1617
*/
1718
export type IdSelector<T, Id extends EntityId> = (model: T) => Id
1819

19-
/**
20-
* @public
21-
*/
22-
export type Dictionary<T, Id extends EntityId> = Partial<Record<Id, T>>
23-
2420
/**
2521
* @public
2622
*/
@@ -31,7 +27,7 @@ export type Update<T, Id extends EntityId> = { id: Id; changes: Partial<T> }
3127
*/
3228
export interface EntityState<T, Id extends EntityId> {
3329
ids: Id[]
34-
entities: Dictionary<T, Id>
30+
entities: Record<Id, T>
3531
}
3632

3733
/**
@@ -42,10 +38,9 @@ export interface EntityDefinition<T, Id extends EntityId> {
4238
sortComparer: false | Comparer<T>
4339
}
4440

45-
export type PreventAny<S, T, Id extends EntityId> = IsAny<
41+
export type PreventAny<S, T, Id extends EntityId> = CastAny<
4642
S,
47-
EntityState<T, Id>,
48-
S
43+
EntityState<T, Id>
4944
>
5045

5146
/**
@@ -157,10 +152,10 @@ export interface EntityStateAdapter<T, Id extends EntityId> {
157152
*/
158153
export interface EntitySelectors<T, V, Id extends EntityId> {
159154
selectIds: (state: V) => Id[]
160-
selectEntities: (state: V) => Dictionary<T, Id>
155+
selectEntities: (state: V) => Record<Id, T>
161156
selectAll: (state: V) => T[]
162157
selectTotal: (state: V) => number
163-
selectById: (state: V, id: Id) => T | undefined
158+
selectById: (state: V, id: Id) => Compute<UncheckedIndexedAccess<T>>
164159
}
165160

166161
/**

packages/toolkit/src/entities/sorted_state_adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function createSortedStateAdapter<T, Id extends EntityId>(
6161
state: R
6262
): void {
6363
newEntities = ensureEntitiesArray(newEntities)
64-
state.entities = {}
64+
state.entities = {} as Record<Id, T>
6565
state.ids = []
6666

6767
addManyMutably(newEntities, state)

packages/toolkit/src/entities/state_selectors.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import type { Selector } from 'reselect'
22
import { createDraftSafeSelector } from '../createDraftSafeSelector'
3-
import type {
4-
EntityState,
5-
EntitySelectors,
6-
Dictionary,
7-
EntityId,
8-
} from './models'
3+
import type { EntityState, EntitySelectors, EntityId } from './models'
94

105
export function createSelectorsFactory<T, Id extends EntityId>() {
116
function getSelectors(): EntitySelectors<T, EntityState<T, Id>, Id>
@@ -27,7 +22,7 @@ export function createSelectorsFactory<T, Id extends EntityId>() {
2722

2823
const selectId = (_: unknown, id: Id) => id
2924

30-
const selectById = (entities: Dictionary<T, Id>, id: Id) => entities[id]
25+
const selectById = (entities: Record<Id, T>, id: Id) => entities[id]
3126

3227
const selectTotal = createDraftSafeSelector(selectIds, (ids) => ids.length)
3328

packages/toolkit/src/entities/unsorted_state_adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function createUnsortedStateAdapter<T, Id extends EntityId>(
6767
newEntities = ensureEntitiesArray(newEntities)
6868

6969
state.ids = []
70-
state.entities = {}
70+
state.entities = {} as Record<Id, T>
7171

7272
addManyMutably(newEntities, state)
7373
}

packages/toolkit/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ export { Tuple } from './utils'
105105

106106
export { createEntityAdapter } from './entities/create_adapter'
107107
export type {
108-
Dictionary,
109108
EntityState,
110109
EntityAdapter,
111110
EntitySelectors,

packages/toolkit/src/tsHelpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export type IsAny<T, True, False = never> =
1818
// test if we are going the left AND right path in the condition
1919
true | false extends (T extends never ? true : false) ? True : False
2020

21+
export type CastAny<T, CastTo> = IsAny<T, CastTo, T>
22+
2123
/**
2224
* return True if T is `unknown`, otherwise return False
2325
* taken from https://github.com/joonhocho/tsdef
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// inlined from https://github.com/EskiMojo14/uncheckedindexed
2+
// relies on remaining as a TS file, not .d.ts
3+
type IfMaybeUndefined<T, True, False> = [undefined] extends [T] ? True : False
4+
5+
const testAccess = ({} as Record<string, 0>).a
6+
7+
export type IfUncheckedIndexedAccess<True, False> = IfMaybeUndefined<
8+
typeof testAccess,
9+
True,
10+
False
11+
>
12+
13+
export type UncheckedIndexedAccess<T> = IfUncheckedIndexedAccess<
14+
T | undefined,
15+
T
16+
>

packages/toolkit/tsup.config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ export default defineConfig((options) => {
203203
if (format === 'cjs' && name === 'production.min') {
204204
writeCommonJSEntry(outputFolder, prefix)
205205
} else if (generateTypedefs) {
206+
if (folder === '') {
207+
// we need to delete the declaration file and replace it with the original source file
208+
fs.rmSync(path.join(outputFolder, 'uncheckedindexed.d.ts'))
209+
210+
fs.copyFileSync(
211+
'src/uncheckedindexed.ts',
212+
path.join(outputFolder, 'uncheckedindexed.ts')
213+
)
214+
}
206215
// TODO Copy/generate `.d.mts` files?
207216
// const inputTypedefsFile = `${outputFilename}.d.ts`
208217
// const outputTypedefsFile = `${outputFilename}.d.mts`

0 commit comments

Comments
 (0)