繁体   English   中英

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

[英]React TypeScript: Argument is not assignable to parameter of type 'never'

我的路由器有一个useReducer并且 initialState 有错误Argument of type 'StateInterface' is not assignable to parameter of type 'never'. 这仅在我在 globalState.tsx 的减速器中使用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 };

Typescript 无法从IActionInterface value: string | boolean确定安全类型转换value: string | boolean value: string | booleanStateInterface warningShow: boolean ,在此代码中 - warningShow: action.value 不能安全地假定value将只包含一个布尔值。

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

warningShow: action.value as boolean

warningMessage: action.value as string

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

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

代替

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

使用两个接口并在此基础上定义类型

interface IActionInterface {
    type: string;
}

interface IMessageActionInterface extends IActionInterface { 
    value: string;
}

interface IShowActionInterface extends IActionInterface {
   value: boolean;
}

type ActionTypes = IMessageActionInterface | IShowActionInterface;

在减速机中

const Reducer = (state: StateInterface, action: ActionTypes) => { }

如果您没有从箭头函数中明确返回某些内容,这似乎很奇怪。 我相信这被解释为“从不”。 所以,对我来说,这似乎是个问题。 如果我错了,对不起。

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

该问题与您构造ActionInterface类型并在减速器中使用它的方式有关。

您需要的是在将操作结构传递给 switch 语句时,让 TypeScript 有一种方法来区分动作结构。

解决这个问题的最好方法是简单地给 TypeScript 一个关于你的操作和你拥有的联合类型的提示。

TypeScript playground看这个例子

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM