// some-component.jsx
import React from 'react'
import { useSelector } from './store'
// ^ instead of import { useSelector } from 'react-redux'
export function SomeComponent() {
const value = useSelector(state => state. /* I want autocomplete here */)
return <p>The value is {value}</p>
}
// Notice that this is a JavaScript file! This means we can't provide types within this file.
It would be nice if useSelector had typings (intellisense) even when importing it into JavaScript files. (when combining slices into a single reducer)
// store.js
import { configureStore } from '@reduxjs/toolkit'
import combineSlices from './combine-slices'
// import slice1, slice2 ...
export const { rootReducer, useSelector } = combineSlices([ slice1, slice2, ... ])
export const store = configureStore({ reducer: rootReducer })
useSelector(state => state. /* VSCode will now provide you with autocomplete! */)
combine-slices.ts implementation
// combine-slices.ts
import { useSelector as useReactReduxSelector } from 'react-redux'
import { combineReducers, Reducer } from 'redux'
type Slice = { name: PropertyKey; reducer: Reducer }
type SliceState<S extends Slice> = {
[K in S['name']]: ReturnType<Extract<S, { name: K }>['reducer']>
}
export default function combineSlices<Slices extends Slice[]>(slices: Slices) {
type RootState = SliceState<Slices[number]>
const reducers = {} as any
for (const slice of slices) {
reducers[slice.name] = slice.reducer
}
const rootReducer = combineReducers<RootState>(reducers)
function useSelector<T>(selector: (state: RootState) => T) {
return useReactReduxSelector<RootState>((state) => selector(state))
}
return {
useSelector,
rootReducer,
}
}
All that is already possible.
The RTK TypeScript documentation and the react-redux TypeScript documentation might give you some hints.
@phryneas Yeah, I know you can provide a type to useSelector using the template syntax useSelector<T>, but this won't work in a JavaScript file (only TypeScript).
I'm specifically considering the case when you want autocomplete (in VSCode) within useSelector in a JavaScript file, because you haven't had the time to turn it into a TypeScript-file yet.
I also provided a working implementation of this above (using slice.name as keys when combing the reducers).
@bergkvist
In a TypeScript file:
export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector
In a JavaScript file:
import {useTypedSelector} from `./thatTypeScriptFile`
Oh, I'm blind! Thanks @phryneas
Of course, the _real_ answer here is "don't mix TS+JS - convert it all to TS" :)
And I'm the TypeScript nerd here, right? :laughing:
Most helpful comment
Of course, the _real_ answer here is "don't mix TS+JS - convert it all to TS" :)