Jan Janssen
Jan Janssen

Reputation: 185

How do i define a property on a Type in a function component? TS2339 ERROR

I have the following code;

import React, { useContext, useReducer, useEffect, } from 'react';

const AppContext = React.createContext({});



const App = () => {
    let initialState = { lang: 'en', color: 'blue'};

    let reducer = (state, action) => {
        if (action === null ) {
            localStorage.removeItem("action");
            return initialState;
        }
        switch (action.type) {
            case "change-language":
                return { ...state, lang: action.payload };
                 default: return {initialState}
        }
    };

    const localState = JSON.parse(localStorage.getItem("state")!);

    let [state, dispatch] = useReducer(reducer, localState || initialState );
    let value = { state, dispatch };

    return (
        <AppContext.Provider value={value}>
            <LanguagePicker />
            <Menu />
        </AppContext.Provider>
    );
}

const Menu = () => <MenuItem />;



const LanguagePicker = () => {
    const  {state, dispatch}  = useContext(AppContext);
    let setLanguage = lang => () => dispatch({ type: "change-language", payload: lang });

    useEffect(() => {
        localStorage.setItem("state", JSON.stringify(state));
      }, [state]);
    return (
        <div>
            <button onClick={setLanguage('en')}>English</button>
            <button onClick={setLanguage('fr')}>French</button>
        </div>  
    );
}

const MenuItem = () => {
    const { state, dispatch } = useContext(AppContext);
    return (
        <div>
            <p>Locale: {state.lang}</p>
        </div>   
    );
}

export default App;

Now, this code runs perfectly fine in JS/JSX, but in typescript it gives the following error.

Property 'state' does not exist on type '{}'.ts(2339)
Property 'dispatch' does not exist on type '{}'.ts(2339)

@

const LanguagePicker = () => {
    const  {state, dispatch}  = useContext(AppContext);

Question obviously becomes; how do i make the property exist on type {}? (Or, fool the compiler into thinking it exists. Why does it give this warning/compiler error in the first place?

I don't get it.

I've tried to define the state in an Interface, then App: React.Component<'any, Interface'>, (as i saw a post where that worked for class components, but to no avail.)

Someone pointing me in the right direction would be highly appreciated.

Upvotes: 2

Views: 1317

Answers (2)

Hamza El Aoutar
Hamza El Aoutar

Reputation: 5657

useContext can infer its types from the context object that is passed in as an argument, which is AppContext.

const AppContext = React.createContext({});

The inferred type is {}, and that's why you are getting that error.

You can fix this by passing in a type generic to createContext:

interface ContextType {
  state?: any;
  dispatch?: any;
}
const AppContext = React.createContext<ContextType>({});

As @skovy said, you should have a better idea of state and dispatch types.

Upvotes: 2

skovy
skovy

Reputation: 5650

The problem is that the type being using for context is {} because that's the value it's being initialized with. If you update the initial call to createContext and pass in the correct type generic this should resolve your issue.

const AppContext = React.createContext<{
  state?: any;
  dispatch?: React.Dispatch<any>;
}>({});

These are pretty loose typings because state can be any value and anything can be dispatched so you may also want to define stronger types for what the actual context value is (but that's up to you and your use case).

Upvotes: 4

Related Questions