import type { ActionCreatorWithPayload, ActionCreatorWithoutPayload, EntityAdapter, EntityId, EntityStateAdapter, Update, } from '@reduxjs/toolkit' import { createEntityAdapter, createSlice } from '@reduxjs/toolkit' function extractReducers( adapter: EntityAdapter, ): EntityStateAdapter { const { selectId, sortComparer, getInitialState, getSelectors, ...rest } = adapter return rest } describe('type tests', () => { test('should be usable in a slice, with all the "reducer-like" functions', () => { type Id = string & { readonly __tag: unique symbol } type Entity = { id: Id } const adapter = createEntityAdapter() const slice = createSlice({ name: 'test', initialState: adapter.getInitialState(), reducers: { ...extractReducers(adapter), }, }) expectTypeOf(slice.actions.addOne).toMatchTypeOf< ActionCreatorWithPayload >() expectTypeOf(slice.actions.addMany).toMatchTypeOf< ActionCreatorWithPayload | Record> >() expectTypeOf(slice.actions.setAll).toMatchTypeOf< ActionCreatorWithPayload | Record> >() expectTypeOf(slice.actions.removeOne).toMatchTypeOf< ActionCreatorWithPayload >() expectTypeOf(slice.actions.addMany).not.toMatchTypeOf< ActionCreatorWithPayload> >() expectTypeOf(slice.actions.setAll).not.toMatchTypeOf< ActionCreatorWithPayload> >() expectTypeOf(slice.actions.removeOne).toMatchTypeOf< ActionCreatorWithPayload >() expectTypeOf(slice.actions.removeMany).toMatchTypeOf< ActionCreatorWithPayload> >() expectTypeOf(slice.actions.removeMany).not.toMatchTypeOf< ActionCreatorWithPayload >() expectTypeOf( slice.actions.removeAll, ).toMatchTypeOf() expectTypeOf(slice.actions.updateOne).toMatchTypeOf< ActionCreatorWithPayload> >() expectTypeOf(slice.actions.updateMany).not.toMatchTypeOf< ActionCreatorWithPayload[]> >() expectTypeOf(slice.actions.upsertOne).toMatchTypeOf< ActionCreatorWithPayload >() expectTypeOf(slice.actions.updateMany).toMatchTypeOf< ActionCreatorWithPayload>> >() expectTypeOf(slice.actions.upsertOne).toMatchTypeOf< ActionCreatorWithPayload >() expectTypeOf(slice.actions.upsertMany).toMatchTypeOf< ActionCreatorWithPayload | Record> >() expectTypeOf(slice.actions.upsertMany).not.toMatchTypeOf< ActionCreatorWithPayload> >() }) test('should not be able to mix with a different EntityAdapter', () => { type Entity = { id: EntityId value: string } type Entity2 = { id: EntityId value2: string } const adapter = createEntityAdapter() const adapter2 = createEntityAdapter() createSlice({ name: 'test', initialState: adapter.getInitialState(), reducers: { addOne: adapter.addOne, // @ts-expect-error addOne2: adapter2.addOne, }, }) }) test('should be usable in a slice with extra properties', () => { type Entity = { id: EntityId; value: string } const adapter = createEntityAdapter() createSlice({ name: 'test', initialState: adapter.getInitialState({ extraData: 'test' }), reducers: { addOne: adapter.addOne, }, }) }) test('should not be usable in a slice with an unfitting state', () => { type Entity = { id: EntityId; value: string } const adapter = createEntityAdapter() createSlice({ name: 'test', initialState: { somethingElse: '' }, reducers: { // @ts-expect-error addOne: adapter.addOne, }, }) }) test('should not be able to create an adapter unless the type has an Id or an idSelector is provided', () => { type Entity = { value: string } // @ts-expect-error const adapter = createEntityAdapter() const adapter2: EntityAdapter = createEntityAdapter({ selectId: (e: Entity) => e.value, }) }) })