React TypeScript:参数不能分配给“从不”类型的参数

时间:2019-11-24 05:18:23

标签: reactjs typescript

我的路由器有一个useReducer,而initialState却有一个错误Argument of type 'StateInterface' is not assignable to parameter of type 'never'.,这仅在我在globalState.tsx的reducer中使用action.value时才开始发生。

(Router.tsx)

    import React, { useReducer } from 'react';
    import { BrowserRouter, Route, Switch } from 'react-router-dom';
    import { Layout } from './components/layout';
    import { Dispatch, Global, InitialState, Reducer } from './globalState';
    import { Home } from './routes/home';
    import { NotFound } from './routes/notFound';

    const Router: React.FC = () => {
      const [global, dispatch] = useReducer(Reducer, InitialState); //<==== Here is the error
      return (
        <Dispatch.Provider value={{ dispatch }}>
          <Global.Provider value={{ global }}>
            <BrowserRouter>
              <Route
                render={({ location }) => (
                  <Layout location={location}>
                    <Switch location={location}>
                      <Route exact path='/' component={Home} />
                      <Route component={NotFound} />
                    </Switch>
                  </Layout>
                )}
              />
            </BrowserRouter>
          </Global.Provider>
        </Dispatch.Provider>
      );
    };

    export { Router };

然后全局状态类似于

(globalState.tsx)

    import { createContext } from 'react';

    interface StateInterface {
      warningMessage: string;
      warningShow: boolean;
    }

    interface ActionInterface {
      type: string;
      value: string | boolean;
    }

    const Dispatch = createContext({
      dispatch: (action: ActionInterface) => {
        //
      },
    });

    const InitialState: StateInterface = {
      warningMessage: '',
      warningShow: false,
    };

    const Global = createContext({
      global: InitialState,
    });

    const WARNING_TOGGLE = 'WARNING_TOGGLE';
    const WARNING_MESSAGE = 'WARNING_MESSAGE';

    const Reducer = (state: StateInterface, action: ActionInterface) => { // <= if I change ActionInterface to any the probem goes away, but my linter then fires of with no any allowed
      switch (action.type) {
        case 'WARNING_TOGGLE':
          return {
            ...state,
            warningShow: action.value, // <== If I remove `action.value and set this to `true` the error goes away
          };
        case 'WARNING_MESSAGE':
          return {
            ...state,
            warningMessage: action.value, // <== If I remove `action.value and set this to `some string` the error goes away
          };
        default:
          return state;
      }
    };

    export { Reducer, InitialState, Dispatch, Global, WARNING_TOGGLE, WARNING_MESSAGE };

和首页

(home.tsx)

    import React, { useContext } from 'react';
    import { Dispatch, Global, WARNING_MESSAGE, WARNING_TOGGLE} from '../globalState';

    const Home: React.FC = () => {
      const { global } = useContext(Global);
      const { dispatch } = useContext(Dispatch);

      const openWarning = () => {
        dispatch({ type: WARNING_TOGGLE, value: true});
      };

      const closeWarning = () => {
        dispatch({ type: WARNING_TOGGLE, value: false});
      };

      const warningMessageVerify = () => {
        dispatch({ type: WARNING_MESSAGE, value: 'Please verify your email'});
      };

      const warningMessageOffine = () => {
        dispatch({ type: WARNING_MESSAGE, value: 'You are now offline'});
      };
      return (
      <section>
      {global.warningShow && <div>Warning Open</div>}
      {!global.warningShow && <div>Warning Closed</div>}
      {global.warningMessage}
      <br/>
        <button onClick={openWarning}>Open Warning</button>
        <button onClick={closeWarning}>Close Warning</button>
        <button onClick={warningMessageVerify}>Verify Email</button>
        <button onClick={warningMessageOffine}>Offline</button>
      </section>
      );
    };

    export { Home };

4 个答案:

答案 0 :(得分:3)

Typescript无法确定从IActionInterface value: string | booleanStateInterface warningShow: boolean的安全类型转换,此代码为warningShow: action.value。它不能安全地假设value仅包含布尔值。

有几种方法可以抑制这种情况,一个简单的方法是-

warningShow: action.value as boolean

warningMessage: action.value as string

as关键字将断言value的类型是booleanstring

答案 1 :(得分:1)

最佳做法是分别为动作创建者定义类型。

代替

{m:for pc | self.eAllContents(pa::PhysicalComponent)}
{m:pc.MatrixFlow()}
{m:endfor}

使用两个接口并基于该接口定义类型

interface ActionInterface {
   type: string;
   value: string | boolean;
}

在Reducer中

interface IActionInterface {
    type: string;
}

interface IMessageActionInterface extends IActionInterface { 
    value: string;
}

interface IShowActionInterface extends IActionInterface {
   value: boolean;
}

type ActionTypes = IMessageActionInterface | IShowActionInterface;

答案 2 :(得分:0)

这似乎很奇怪,如果您没有从箭头函数中显式返回某些内容。我认为这被解释为“从不”。因此,对我来说,这似乎是个问题。如果我错了,对此表示抱歉。

const Dispatch = createContext({
  dispatch: (action: ActionInterface) => {
    //
  },
});

答案 3 :(得分:0)

该问题与您构造ActionInterface类型并将其用于化简器的方式有关。

您需要的是让TypeScript在将其传递给switch语句时区分操作结构。

解决此问题的最佳方法是简单地给TypeScript一个有关您的操作和所拥有的联合类型的提示。

请看TypeScript playground

中的示例