My FeedDiscussionsHashnode Enterprise
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
React with TypeScript

React with TypeScript

Saurav Kumar's photo
Saurav Kumar
·Feb 12, 2022·

6 min read

TypeScript and React are two of the most popular technologies nowadays in web development. In this article, we will see how to use TypeScript in React.

Before starting let see what are these technologies, you may know React is a javascript library for creating interactive UI's (User Interfaces) for our web apps, but what is TypeScript there's a misconception a beginner can make when they come across the word Typescript that its a language that's going to replace javascript but nothing is like that, typescript is a superset of javascript and checks your code for bugs before the run time which is a great advantage for developers as it shows you the error while coding and also it makes easy in refactoring and collaborating especially in large applications.

Now we are done with the definitions so let's get started.

Setup

To use typescript in react use this command to initialize a react project with typescript.

npx create-react-app name-of-app --template typescript

Now if you go inside your app you will notice files with .ts and .tsx extensions and also a tsconfig.json file which specifies the root files and the compiler options required to compile the project.

Component Type

There are different ways to define a type to a functional component some of them are shown below:

import { ReactElement, ReactNode } from "react"

const App = (): JSX.Element => <div>Hello</div>;
const App = (): ReactElement => <div>Hello</div>;
const App = (): ReactNode => <div>Hello</div>;

You must have noticed some extra code is written after the colon those are the return type of the components.

The first one is JSX.Element means the component is returning a JSX and if the component is returning anything other than JSX it will throw an error.

The second one is ReactElement which also returns a JSX Element.

The third one is ReactNode which implies that the component should return any one of these types - boolean, ReactChild, ReactFragment, null or undefined.

Component props Type

Let's now see how can we give component props a type and it is compulsory to give props a type otherwise props will show an error that the parameter has an "any" type which means that the type could be anything and typescript wants you to give the props a type.

A component prop type could be anything from like string, number, boolean, array, object, JSX, setState, etc, and In TypeScript, it supports the same types as you would expect in JavaScript but when it comes to providing a type for an object we just don't give it a type "object" as an object will have different properties and those properties will have their own types, to do that we use something called Type aliases and Interface.

// Using Type aliases
export type UserProps = {
      id: string;
      name: string;
      age: number
}

const User = ({ id, name, age }:UserProps):JSX.Element => {
   return (
     . . .
   )
}
------ OR -------
// Using Interface
export interface UserProps {
     id: string;
     name: string;
     age: number
}

const User = ({ id, name, age }:UserProps):JSX.Element => {
   return (
     . . .
   )
}

Type and Interface do the same thing so you can choose any one of them to use but because of some differences like type cannot be re-opened to add new properties vs an interface that is very extendable so it is preferred to use interface for any 3rd party library where type is preferred for your React Component Props and State.

Defining useState Type

Giving useState a type is important as it prevents you from passing any value whose type is different from the type of your initial value. Usually, we don't have to give a type for simple values like a string, number, or a boolean, typescript automatically checks from what you have provided as an initialvalue.

// for basic values
const [name, setName] = useState("");
const [age, setAge] = useState(20);
const [toggle, setToggle] = useState(false);

useEffect(() => {
  setName(100) // shows an error (Argument of type 'number' is not assignable to parameter of type 'string')
}, [])

For values like an array, object we have to declare a type explicitly, let's see how it can be done.

// an array of numbers
const [numArray, setNumArray] = useState<number[]>([])

// an array of objects
type User = {
   id: string;
   name: string;
   age: number
}
const [ users, setUsers] = useState<User[]>([]);

// an object
const [ user, setUser] = useState<User>({} as User);

Sometimes your state can have more than one type, for example, you initialized your hook with a null value and then set data later but it will give an error as soon as you provide the state with a value other than null but it is solved using something called Union type. A union type is a type that is formed from more than one type and any one of those types will represent the value.

type User = {
   id: string;
   name: string;
   age: number
}
const [ user, setUser ] = useState<User | null>(null);

Now the user state will have null as well as User type.

Defining useRef type

useRef hook is used to access a DOM element and to give useRef a type you have to provide the Html element that you are referencing to like if you are referencing to a div element then use HTMLDivElement or if you are referencing an input element then use HTMLInputElement and initialized as null.

// accessing an input element
const inputRef = useRef<HTMLInputElement>(null);
//accessing a div element
const divRef = useRef<HTMLDivElement>(null);

In this case, the return reference will have a .current property which you can access now.

useContext

To give type to useContext hook, you have to give types to the values that you are passing in the context Provider value prop

// context type
type UserContextType = {
   login: boolean;
   token: string | null;
   name: string;
   age: number
}

const UserContext = React.createContext<UserContextType>({} as UserContextType);

// Provider in your app
const contextValues: UserContextType = {
   login: false,
   token: null
   name: "user name",
   age: 20;
};

export const UserProvider = () => (
  <UserContext.Provider value={contextValues}>...</UserContext.Provider>
);

export function useUser(){
     return useContext(UserContex);
}

useReducer

In useReducer the type is declared to the parameters of the reducer function, we have to give the state a type as well as the action.

const initialState = {
   count: 0
}

const [state, dispatch] = useReducer(reducer, initialState);

// useing Discriminated Unions for reducer actions type.
type ACTIONTYPE = {
  | { type: "INCREMENT", payload: number }
  | { type: "DECREMENT", payload: number }
} 

function reducer(state: typeof initialState, action: ACTIONTYPE) {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + action.payload };
    case "DECREMENT":
      return { count: state.count - action.payload };
    default:
      return state;
  }
}

Hope this article helped you in understanding how to use Typescript in React.