My Router has a useReducer
and the initialState has the error Argument of type 'StateInterface' is not assignable to parameter of type 'never'.
this only started happening when I use action.value
in the reducer in globalState.tsx
(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 };
then global state looks like
(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 };
and Home
(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 };
ts(2322) arr[0] = 'a'; We declared an empty array and it got assigned a type of never[] . This type represents an array that will never contain any elements (will always be empty). To solve this, we have to explicitly type the empty array.
The error "Type is not assignable to type 'never'" occurs when we declare an empty state array with the useState hook but don't type the array. To solve the error, use a generic to type the state array, e.g. const [arr, setArr] = useState<string[]>([]) . Here is an example of how the error occurs. Copied!
Never is a new type in TypeScript that denotes values that will never be encountered. Example 1: The null can be assigned to void but null cannot be assigned to never type variables, nor can any other type be assigned including any. Javascript.
The "Type 'string' is not assignable to type" TypeScript error occurs when we try to assign a value of type string to something that expects a different type, e.g. a more specific string literal type or an enum. To solve the error use a const or a type assertion.
Typescript is not able to determine a safe typecast from IActionInterface
value: string | boolean
to StateInterface
warningShow: boolean
, in this code - warningShow: action.value
. It cannot safely presume that value
will only contain a boolean.
There are several ways to suppress this, a simple one is -
warningShow: action.value as boolean
warningMessage: action.value as string
The as
keyword will assert that the type of value
is a boolean
or string
.
it is a best practice to define types for action creators separately.
Instead of
interface ActionInterface {
type: string;
value: string | boolean;
}
use two interface and define the type based on that
interface IActionInterface {
type: string;
}
interface IMessageActionInterface extends IActionInterface {
value: string;
}
interface IShowActionInterface extends IActionInterface {
value: boolean;
}
type ActionTypes = IMessageActionInterface | IShowActionInterface;
In Reducer
const Reducer = (state: StateInterface, action: ActionTypes) => { }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With