簡體   English   中英

TS2339:“DefaultRootState”類型上不存在屬性“tsReducer”

[英]TS2339: Property 'tsReducer' does not exist on type 'DefaultRootState'

為上述問題而苦苦掙扎。 看到類似的問題,但無法弄清楚。

下面的代碼是我第一次嘗試在使用 .js 和 .jsx 的現有 React 項目中使用 TypeScript 打開和關閉對話框。

import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import {useDispatch, useSelector} from 'react-redux';
import {closeTsDialog} from '../actions/tsDialog'
import {ActionTypes} from '../actions/types';

const TsApp = (): JSX.Element => {
    const dispatch = useDispatch();

// ERROR SHOWS UP ON LINE BELOW "state?.tsReducer?.isDialogOpen"
    const isDialogOpen = useSelector(state => state?.tsReducer?.isDialogOpen);
    const state = useSelector(s => s);
    console.log('->>>>>> state', state);


    // main tsx excluded to allow for posting on stackoverflow
};


export default TsApp;
import {TsDialogAction} from "../actions/tsDialog";


const initialState = {
    id: 0,
    isDialogOpen: false
};

const tsReducer = (state: TsDialogAction = initialState, action: Action) => {
    switch (action.type) {
        case ActionTypes.closeDialog: {
            return {...state, isDialogOpen: false};
        }
        case ActionTypes.openDialog: {
            return {...state, isDialogOpen: true};
        }
        default:
            return state;
    }
};

export default tsReducer;

從'./types'導入{ActionTypes};

導出接口 TsDialogAction { isDialogOpen: boolean number: number }

導出接口 CloseTsDialog { 類型:ActionTypes.closeDialog 有效負載:TsDialogAction }

導出接口 OpenTsDialog { 類型:ActionTypes.openDialog 有效負載:TsDialogAction }

導出接口增量 { 類型:ActionTypes.increment 有效負載:TsDialogAction }

導出接口減量{類型:ActionTypes.減量負載:TsDialogAction}

export const closeTsDialog = (id: number) => ({type: ActionTypes.closeDialog, payload: id}); export const openTsDialog = (id: number) => ({type: ActionTypes.openDialog, payload: id}); export const incrementAction = (id: number) => ({type: ActionTypes.increment, payload: id}); export const decrementAction = (id: number) => ({type: ActionTypes.decrement, payload: id});

它在抱怨這種類型。 快速解決方案是添加any作為狀態類型。

正確的解決方案需要以下兩個步驟:

  1. 在 Root Reducer 中創建 RootState 類型。
export const rootReducer = combineReducers({
  dashboard: dashboardReducer,
  user: userReducer
});

export type RootState = ReturnType<typeof rootReducer>
  1. 為狀態對象提供 RootState 類型。
  let userData = useSelector((state: RootState) => {
    return state.user.data;
  });

您需要在選擇器中聲明state參數的類型,例如:

const isDialogOpen = useSelector( (state: RootState) => state.tsReducer.isDialogOpen);

請參閱有關 TypeScript 使用的 Redux 文檔,以及有關靜態類型的 React-Redux 文檔頁面以獲取示例。

(另外,作為風格說明:請不要在根狀態中調用該tsReducer 。給它一個與其正在處理的數據匹配的名稱,例如state.ui 。)

如果您使用 react-redux,另一個開箱即用的解決方案是使用RootStateOrAny

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

// and then use it like so in your component
...
const authState = useSelector((state: RootStateOrAny) => state.auth);
...


對我來說,比在 useSelector 中指定狀態更好的解決方案如下。
node_modules/@types/react-redux/index.d.ts ,您可以使用模塊擴充。

/**
 * This interface can be augmented by users to add default types for the root state when
 * using `react-redux`.
 * Use module augmentation to append your own type definition in a your_custom_type.d.ts file.
 * https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
 */
// tslint:disable-next-line:no-empty-interface
export interface DefaultRootState {}

執行以下操作

  1. 在 reducer src/reducer/index.ts
const reducers = combineReducers({
  userReducer,
});

export type AppState = ReturnType<typeof reducers>;
  1. 創建新的your_custom_type.d.ts (我更喜歡 react-redux.d.ts)。
    src/@types/your_custom_type.d.ts
import 'react-redux';

import { AppState } from '../reducers';

declare module 'react-redux' {
  interface DefaultRootState extends AppState { };
}
  1. 在 tsconfig.json 中添加typeRoots
{
  "compilerOptions": {
    ...
    "typeRoots": ["src/@types"]
  }
}

您可以在不指定 AppState 的情況下使用如下

import React, { memo } from 'react';
import { useSelector } from 'react-redux';

export default memo(() => {
  const isLoggedIn = useSelector(
    ({ userReducer }) => userReducer.isLoggedIn
  );
  return <div>{isLoggedIn}</div>;
});

這些都是有用的文章。

  1. https://redux.js.org/recipes/usage-with-typescript#define-root-state-and-dispatch-types
  2. https://redux.js.org/recipes/usage-with-typescript#define-typed-hooks

所以首先定義RootStateAppDispatch如下:

//at store/index.ts
const rootReducer = combineReducers({
  tsReducer: tsReducer
});
const store = createStore(rootReducer)

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

然后定義可以在組件中使用的鈎子( useAppDispatchuseAppSelector )。

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

export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

並在組件上使用它,如下所示:

import {useAppSelector} from '../store/hooks'
//...
const TsApp = (): JSX.Element => {
    const dispatch = useDispatch();

// ERROR should be fixed
    const isDialogOpen = useAppSelector(state => state.tsReducer.isDialogOpen);
};

這對我有用

import { RootStateOrAny, useSelector } from "react-redux"

const search = useSelector((state: RootStateOrAny) => state.searchObj.values)

在非反應組件中,你可以做的只是函數或鈎子

import {store} from "../redux/store"

const search: SearchProps | any = store.getState().searchObj.values

它只是你需要滿足這個鈎子的類型, useSelector接受DefaultRootState類型,你可以通過這個覆蓋它的默認類型

type User = {
  firstname: string;
  lastname: string;
};
type SelectorTypes = {
  users: User[];
  //...other reducers
};
const router = useSelector<SelectorTypes>((state) => state.users);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM