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

IT技术 reactjs typescript redux
2021-05-25 19:21:36

我有一个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;

然后在我的src/index.tsx

import {Provider} from 'react-redux';

const store = createStore(allReducers);

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

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

import {useSelector} from 'react-redux';

const App = () => {
   const counter = useSelector(state => state.counter);
   return (
      <h1>counter {counter}</h1>
   );
};

报错的state.counter部分是useSelector

> Property 'counter' does not exist on type 'DefaultRootState'.ts(2339)

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

4个回答

非 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

短暂的停顿以解压第 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 意思是“我想要用于将操作分派到商店的分派对象。”

现在将这些部分放在一起!:从商店中获取 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

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


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

这对我有用。

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

const { domain } = useSelector(
 (state: RootStateOrAny) => state.currentSite?.site,
);

这确实是一个 TypeScript 问题。为了让我的应用程序编译并与 Redux 一起工作,我做了一些更改。我知道我们不应该发布链接,但https://github.com/piotrwitek/react-redux-typescript-guide这是一个很好的资源!根据那里的例子,我解决了我的问题:

我更改了 useSelector 以将类型定义为状态,这解决了原始错误。

import {RootState} from 'typesafe-actions';
const counter = useSelector((state: RootState) => state.counter);

但什么是RootStateRootState 是在src/store/types.d.ts文件中创建的自定义类型

import {StateType, ActionType} from 'typesafe-actions';

declare module 'typesafe-actions' {
  export type Store = StateType<typeof import('./index').default>;

  export type RootState = StateType<typeof import('./root-reducer').default>;

  export type RootAction = ActionType<typeof import('./root-action').default>;

  interface Types {
    RootAction: RootAction;
  }
}

这个错误是typescript显示的错误

我将根据mac用户进行解释。将鼠标光标放在 userSelector 上并在按住命令键的同时单击。下面路径中的文件将被打开(如果没有打开,请手动打开) /Users/{username}/Library/Caches/typescript /3.9/node_modules/@types/react-redux/index.d.ts

并将以下代码修改为

export function useSelector<TState = DefaultRootState, TSelected = unknown>()

(如下)

export function useSelector<TState = any, TSelected = unknown>()

(如果你这样做,错误可能会消失。)

报错的原因是jsconfig.json的checkJs=true设置导致vscode使用typescript检查类型,但是是因为state的类型没有定义而出现的错误。

输入任何以上意味着您不关心状态的类型。作为参考,要在 JavaScript 中正确输入类型,您需要精心编写 JSDoc。事实上,用typescript写比那样写要好。