类型“DefaultRootState”上不存在属性“y”

Pet*_*sma 2 typescript reactjs redux

我有一个src/reducers/index.tsx文件,我在其中输出所有减速器:

import counterReducer from '../reducers/counter';
import loggedReducer from '../reducers/isLogged';
import {combineReducers} from 'redux';

const allReducers = combineReducers({
   counter: counterReducer,
   isLogged: loggedReducer,
});

export default allReducers;
Run Code Online (Sandbox Code Playgroud)

然后在我的src/index.tsx

import {Provider} from 'react-redux';

const store = createStore(allReducers);

ReactDOM.render(
   <React.Fragment>
      <Provider store={store}>
        <App />
      </Provider>,
   document.getElementById('root'),
);
Run Code Online (Sandbox Code Playgroud)

最后在我的src/app.tsx我有:

import {useSelector} from 'react-redux';

const App = () => {
   const counter = useSelector(state => state.counter);
   return (
      <h1>counter {counter}</h1>
   );
};
Run Code Online (Sandbox Code Playgroud)

错误是报告在的state.counter部分useSelector

> Property 'counter' does not exist on type 'DefaultRootState'.ts(2339)
Run Code Online (Sandbox Code Playgroud)

看起来商店从未真正创建过?

Ant*_*hew 8

非 hacky 回答入站!

最短的答案:

链接到 Redux Toolkit 文档以创建类型化的 react-redux 钩子:https ://react-redux.js.org/using-react-redux/usage-with-typescript#define-root-state-and-dispatch-types

(虽然这是 Redux Toolkit 文档的链接,但我相信这种技术仍然适用于 "vanilla" react-redux。如果我错了,请有人用评论纠正我。)

简答:

useSelector本身挂钩是不知道应该应用到你想使用的状态打字的。您必须做几行工作才能获得类型安全!使用链接中显示的技术,每次使用它时,您都将获得适合您的状态的类型。您将创建一个单行自定义钩子,该钩子利用useSelector带有从根状态推断出的类型的本机钩子来找出您的状态应该是什么类型。

更长的答案:

useSelector本身挂钩是不知道应该应用到你想使用的状态打字的。为了使您的商店类型被捕获并应用于您的useSelector挂钩,您需要跳过两个小环。当我们在做的时候,我们也会照顾好你的useDispatch钩子。

第1步

让我们从 store 中获取推断的类型。为此,我们将前往创建我们的 store 的位置,并使用一些 Typescript 魔法从状态中获取推断类型:

// Copied from Redux Toolkit docs that are linked above
// store.ts

import rootReducer from './rootReducer'

const store = createStore(rootReducer)

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
Run Code Online (Sandbox Code Playgroud)

短暂的停顿以解压第 6 行和第 7 行:

第 6 行: export type RootState = ReturnType<typeof store.getState>

  • ReturnType 表示“函数的返回类型”。

  • typeof 意思是“告诉我这东西的类型是什么。”

  • store.getState 是一个函数,它返回当前在商店中的状态对象。

现在将这些部分放在一起!:无论从 store.getState 返回什么,我都希望将类型存储为RootState变量!


第 7 行: export type AppDispatch = typeof store.dispatch

  • typeof 意思是“告诉我这东西的类型是什么。”
  • store.dispatch 意思是“我想要用于将操作分派到商店的分派对象。”

现在把这些部分放在一起!:从 store 中获取 dispatch 对象,将它分解成它的类型,然后将它存储在AppDispatch变量中!

第2步

现在我们已经从 store 和 dispatch 推断出类型,我们可以将它们应用于我们的钩子。我们将通过创建一个自定义钩子来做到这一点,这样我们就不必每次去使用它们时都输入我们的钩子:

// Copied from Redux Toolkit docs that are linked above
// hooks.ts

import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
Run Code Online (Sandbox Code Playgroud)

在这里,我们将我们创建的类型store.ts应用到我们通常在 中使用的useDispatchuseSelector钩子react-redux。从现在开始,当您使用新的自定义钩子时,您将为您设置类型!


瞧!您现在在 react-redux 钩子实现中具有类型安全性!


小智 7

这对我有用。

import { RootStateOrAny, useSelector } from 'react-redux';

const { domain } = useSelector(
 (state: RootStateOrAny) => state.currentSite?.site,
);
Run Code Online (Sandbox Code Playgroud)