skip to Main Content

Im converting an existing Reactjs project to typescript. Im also learning TS as I go on this project. I am getting a few errors that I am not sure how to navigate and cant seem to find a good answer on google.

One of my errors, I am pulling a useState boolean from my useContext into my protected route:

Property ‘loggedIn’ does not exist on type ‘{}’.

Protected Route:

import { Navigate } from "react-router-dom";
import { useAuthContext } from "../context/AuthContext";
import { ReactNode } from "react";

// type ProtectedRouteProps = {
//   children: ReactNode;
// };

export const ProtectedRoute = ({ children }: any) => {
  const { loggedIn } = useAuthContext();
  if (!loggedIn) {
    // user is not authenticated
    return <Navigate to="/" />;
  }
  return children;
};

My AuthContext:

import { useState, createContext, useContext, ReactNode } from "react";
import { useNavigate } from "react-router-dom";

const AuthContext = createContext({});

export function useAuthContext() {
  return useContext(AuthContext);
}
type AuthProviderProps = {
  children: ReactNode;
};

export function AuthProvider({ children }: AuthProviderProps) {
  const [loggedIn, setLoggedIn] = useState<boolean>(
    localStorage.getItem("loggedIn") === "true"
  );

  const [selectedDogs, setSelectedDogs] = useState<number[]>([]);
  const navigate = useNavigate();

  function setDogMatch(data: number[]) {
    setSelectedDogs(data);
    navigate("/dog-match");
  }

  return (
    <AuthContext.Provider
      value={{
        loggedIn,
        setLoggedIn,
        selectedDogs,
        setDogMatch,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

Not sure what I am missing for that type and where it would need to be set if in my AuthContext or Protected Route.

I also created another error myself my SearchFilter.tsx. Error:

Property ‘map’ does not exist on type ‘string | number’.
Property ‘map’ does not exist on type ‘string’.

Heres my SearchFilter.tsx not sure what to do with that map type error. my SearchFilter.tsx takes in data from an API containing strings(dog breeds) and numbers(dog ids) i believe i have my types set up correct for that :

import Select from "react-select";

type Props ={
  props: string | number
  data: string | number
  name: string
}

export default function SearchFilters(props: Props) {
  const options =
    props.data &&
    props.data.map((data: Props) => {
      return { value: data, label: data };
    });

  return (
    <div className="dropdown-container">
      <h4>{props.name}</h4>
      <Select options={options} isSearchable={true} {...props} />
    </div>
  );
}

Thanks for the help new to TypeScript and learning as I go on this project!

2

Answers


  1. 1. Property ‘loggedIn’ does not exist on type ‘{}’.

    export function useAuthContext() {
      return <{ loggedIn: any }>useContext(AuthContext);
    }
    

    2. Property ‘map’ does not exist on type ‘string | number’. Property ‘map’ does not exist on type ‘string’.

    You’re calling .map() on props.data, which is of type string | number. .map() is only callable on objects which are iterable. Your SearchFilter.tsx is unclear about the exact type, so I’m only guessing.

    type Props = {
      [_: string | number]: any
    }
    

    This will make this error go away, but may introduce another error somewhere else.

    Login or Signup to reply.
    1. Currently the type of the value the context holds is being inferred from the default value given to createContext, which does not have a loggedIn field.

    You could instead set the type explicitly through the generic parameter to createContext, e.g. createContext<T>(defaultVal). Alternatively, pass a default value that contains all the type information.

    const AuthContext = createContext({
        loggedIn: false,
        setLoggedIn: (val: boolean) => {},
        selectedDogs: [] as number[],
        setDogMatch: (val: number[]) => {}
    });
    
    1. It seems like props.data should be an array, but you have typed it as either a string or a number.
    type Props = {
      data: (string | number)[]
      name: string
    };
    
    const options = props.data?.map(data => ({ value: data, label: data }));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search