Skip to content

prevent any-casting of S generic on entityAdapter reducer-like f… #436

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions docs/api/createEntityAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ export interface Dictionary<T> extends DictionaryNum<T> {

export type Update<T> = { id: EntityId; changes: Partial<T> }

export type EntityMap<T> = (entity: T) => T

export interface EntityState<T> {
ids: EntityId[]
entities: Dictionary<T>
Expand Down Expand Up @@ -171,9 +169,6 @@ export interface EntityStateAdapter<T> {
state: S,
entities: PayloadAction<T[]>
): S

map<S extends EntityState<T>>(state: S, map: EntityMap<T>): S
map<S extends EntityState<T>>(state: S, map: PayloadAction<EntityMap<T>>): S
}

export interface EntitySelectors<T, V> {
Expand Down Expand Up @@ -208,7 +203,6 @@ The primary content of an entity adapter is a set of generated reducer functions
- `updateMany`: accepts an array of update objects, and updates all corresponding entities
- `upsertOne`: accepts a single entity. If an entity with that ID exists, the fields in the update will be merged into the existing entity, with any matching fields overwriting the existing values. If the entity does not exist, it will be added.
- `upsertMany`: accepts an array of entities that will be upserted.
- `map`: accepts a callback function that will be run against each existing entity, and may return a change description object. Afterwards, all changes will be merged into the corresponding existing entities.

Each method has a signature that looks like:

Expand Down
3 changes: 0 additions & 3 deletions etc/redux-toolkit.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,6 @@ export interface EntityAdapter<T> extends EntityStateAdapter<T> {
sortComparer: false | Comparer<T>;
}

// @alpha (undocumented)
export type EntityMap<T> = (entity: T) => T;

// @alpha (undocumented)
export interface EntityState<T> {
// (undocumented)
Expand Down
1 change: 0 additions & 1 deletion src/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export {
EntityState,
EntityAdapter,
Update,
EntityMap,
IdSelector,
Comparer
} from './models'
76 changes: 49 additions & 27 deletions src/entities/models.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PayloadAction } from '../createAction'
import { IsAny } from '../tsHelpers'

/**
* @alpha
Expand Down Expand Up @@ -34,11 +35,6 @@ export interface Dictionary<T> extends DictionaryNum<T> {
*/
export type Update<T> = { id: EntityId; changes: Partial<T> }

/**
* @alpha
*/
export type EntityMap<T> = (entity: T) => T

/**
* @alpha
*/
Expand All @@ -52,50 +48,76 @@ export interface EntityDefinition<T> {
sortComparer: false | Comparer<T>
}

export type PreventAny<S, T> = IsAny<S, EntityState<T>, S>

export interface EntityStateAdapter<T> {
addOne<S extends EntityState<T>>(state: S, entity: T): S
addOne<S extends EntityState<T>>(state: S, action: PayloadAction<T>): S
addOne<S extends EntityState<T>>(state: PreventAny<S, T>, entity: T): S
addOne<S extends EntityState<T>>(
state: PreventAny<S, T>,
action: PayloadAction<T>
): S

addMany<S extends EntityState<T>>(state: S, entities: T[]): S
addMany<S extends EntityState<T>>(state: S, entities: PayloadAction<T[]>): S
addMany<S extends EntityState<T>>(state: PreventAny<S, T>, entities: T[]): S
addMany<S extends EntityState<T>>(
state: PreventAny<S, T>,
entities: PayloadAction<T[]>
): S

setAll<S extends EntityState<T>>(state: S, entities: T[]): S
setAll<S extends EntityState<T>>(state: S, entities: PayloadAction<T[]>): S
setAll<S extends EntityState<T>>(state: PreventAny<S, T>, entities: T[]): S
setAll<S extends EntityState<T>>(
state: PreventAny<S, T>,
entities: PayloadAction<T[]>
): S

removeOne<S extends EntityState<T>>(state: S, key: EntityId): S
removeOne<S extends EntityState<T>>(state: S, key: PayloadAction<EntityId>): S
removeOne<S extends EntityState<T>>(state: PreventAny<S, T>, key: EntityId): S
removeOne<S extends EntityState<T>>(
state: PreventAny<S, T>,
key: PayloadAction<EntityId>
): S

removeMany<S extends EntityState<T>>(state: S, keys: EntityId[]): S
removeMany<S extends EntityState<T>>(
state: S,
state: PreventAny<S, T>,
keys: EntityId[]
): S
removeMany<S extends EntityState<T>>(
state: PreventAny<S, T>,
keys: PayloadAction<EntityId[]>
): S

removeAll<S extends EntityState<T>>(state: S): S
removeAll<S extends EntityState<T>>(state: PreventAny<S, T>): S

updateOne<S extends EntityState<T>>(state: S, update: Update<T>): S
updateOne<S extends EntityState<T>>(
state: S,
state: PreventAny<S, T>,
update: Update<T>
): S
updateOne<S extends EntityState<T>>(
state: PreventAny<S, T>,
update: PayloadAction<Update<T>>
): S

updateMany<S extends EntityState<T>>(state: S, updates: Update<T>[]): S
updateMany<S extends EntityState<T>>(
state: S,
state: PreventAny<S, T>,
updates: Update<T>[]
): S
updateMany<S extends EntityState<T>>(
state: PreventAny<S, T>,
updates: PayloadAction<Update<T>[]>
): S

upsertOne<S extends EntityState<T>>(state: S, entity: T): S
upsertOne<S extends EntityState<T>>(state: S, entity: PayloadAction<T>): S
upsertOne<S extends EntityState<T>>(state: PreventAny<S, T>, entity: T): S
upsertOne<S extends EntityState<T>>(
state: PreventAny<S, T>,
entity: PayloadAction<T>
): S

upsertMany<S extends EntityState<T>>(state: S, entities: T[]): S
upsertMany<S extends EntityState<T>>(
state: S,
state: PreventAny<S, T>,
entities: T[]
): S
upsertMany<S extends EntityState<T>>(
state: PreventAny<S, T>,
entities: PayloadAction<T[]>
): S

map<S extends EntityState<T>>(state: S, map: EntityMap<T>): S
map<S extends EntityState<T>>(state: S, map: PayloadAction<EntityMap<T>>): S
}

export interface EntitySelectors<T, V> {
Expand Down
34 changes: 0 additions & 34 deletions src/entities/sorted_state_adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,40 +331,6 @@ describe('Sorted State Adapter', () => {
})
})

it('should let you map over entities in the state', () => {
const firstChange = { ...TheGreatGatsby, title: 'First change' }
const secondChange = { ...AClockworkOrange, title: 'Second change' }

const withMany = adapter.setAll(state, [
TheGreatGatsby,
AClockworkOrange,
AnimalFarm
])

const withUpdates = adapter.map(withMany, book =>
book.title === TheGreatGatsby.title
? firstChange
: book.title === AClockworkOrange.title
? secondChange
: book
)

expect(withUpdates).toEqual({
ids: [AnimalFarm.id, TheGreatGatsby.id, AClockworkOrange.id],
entities: {
[AnimalFarm.id]: AnimalFarm,
[TheGreatGatsby.id]: {
...TheGreatGatsby,
...firstChange
},
[AClockworkOrange.id]: {
...AClockworkOrange,
...secondChange
}
}
})
})

it('should let you add one entity to the state with upsert()', () => {
const withOneEntity = adapter.upsertOne(state, TheGreatGatsby)
expect(withOneEntity).toEqual({
Expand Down
22 changes: 2 additions & 20 deletions src/entities/sorted_state_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import {
IdSelector,
Comparer,
EntityStateAdapter,
Update,
EntityMap,
EntityId
Update
} from './models'
import { createStateOperator } from './state_adapter'
import { createUnsortedStateAdapter } from './unsorted_state_adapter'
Expand Down Expand Up @@ -72,21 +70,6 @@ export function createSortedStateAdapter<T>(
}
}

function mapMutably(updatesOrMap: EntityMap<T>, state: R): void {
const updates: Update<T>[] = state.ids.reduce(
(changes: Update<T>[], id: EntityId) => {
const change = updatesOrMap(state.entities[id]!)
if (change !== state.entities[id]) {
changes.push({ id, changes: change })
}
return changes
},
[]
)

updateManyMutably(updates, state)
}

function upsertOneMutably(entity: T, state: R): void {
return upsertManyMutably([entity], state)
}
Expand Down Expand Up @@ -151,7 +134,6 @@ export function createSortedStateAdapter<T>(
setAll: createStateOperator(setAllMutably),
addMany: createStateOperator(addManyMutably),
updateMany: createStateOperator(updateManyMutably),
upsertMany: createStateOperator(upsertManyMutably),
map: createStateOperator(mapMutably)
upsertMany: createStateOperator(upsertManyMutably)
}
}
34 changes: 0 additions & 34 deletions src/entities/unsorted_state_adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,40 +250,6 @@ describe('Unsorted State Adapter', () => {
expect(entities.c).toBeTruthy()
})

it('should let you map over entities in the state', () => {
const firstChange = { ...TheGreatGatsby, title: 'First change' }
const secondChange = { ...AClockworkOrange, title: 'Second change' }

const withMany = adapter.setAll(state, [
TheGreatGatsby,
AClockworkOrange,
AnimalFarm
])

const withUpdates = adapter.map(withMany, book =>
book.title === TheGreatGatsby.title
? firstChange
: book.title === AClockworkOrange.title
? secondChange
: book
)

expect(withUpdates).toEqual({
ids: [TheGreatGatsby.id, AClockworkOrange.id, AnimalFarm.id],
entities: {
[TheGreatGatsby.id]: {
...TheGreatGatsby,
...firstChange
},
[AClockworkOrange.id]: {
...AClockworkOrange,
...secondChange
},
[AnimalFarm.id]: AnimalFarm
}
})
})

it('should let you add one entity to the state with upsert()', () => {
const withOneEntity = adapter.upsertOne(state, TheGreatGatsby)
expect(withOneEntity).toEqual({
Expand Down
22 changes: 2 additions & 20 deletions src/entities/unsorted_state_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
EntityStateAdapter,
IdSelector,
Update,
EntityMap,
EntityId
} from './models'
import { createStateOperator } from './state_adapter'
Expand Down Expand Up @@ -57,7 +56,7 @@ export function createUnsortedStateAdapter<T>(
}
}

function removeAll<S extends R>(state: S): S {
function removeAll(state: R): any {
return Object.assign({}, state, {
ids: [],
entities: {}
Expand Down Expand Up @@ -120,22 +119,6 @@ export function createUnsortedStateAdapter<T>(
}
}

function mapMutably(map: EntityMap<T>, state: R): void {
const changes: Update<T>[] = state.ids.reduce(
(changes: Update<T>[], id: EntityId) => {
const change = map(state.entities[id]!)
if (change !== state.entities[id]) {
changes.push({ id, changes: change })
}
return changes
},
[]
)
const updates = changes.filter(({ id }) => id in state.entities)

return updateManyMutably(updates, state)
}

function upsertOneMutably(entity: T, state: R): void {
return upsertManyMutably([entity], state)
}
Expand Down Expand Up @@ -167,7 +150,6 @@ export function createUnsortedStateAdapter<T>(
upsertOne: createStateOperator(upsertOneMutably),
upsertMany: createStateOperator(upsertManyMutably),
removeOne: createStateOperator(removeOneMutably),
removeMany: createStateOperator(removeManyMutably),
map: createStateOperator(mapMutably)
removeMany: createStateOperator(removeManyMutably)
}
}
1 change: 0 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ export {
EntityState,
EntityAdapter,
Update,
EntityMap,
IdSelector,
Comparer
} from './entities/models'
Expand Down
Loading