ReactJs with Typescript
(Useful : 1] CheatSheet 2] Click)
React is one of the most popular front-end JavaScript libraries for building user interfaces. Using TypeScript for your React projects can lead to a more robust codebase with less errors.
Some advantages of using Typescript with ReactJs are as followed :
- Better Autocompletion - It prevents us from remembering props and function parameters, which allows you to focus more on building the application.You won't need to check what the state looks like or what props your component accepts; your editor will automatically suggest the right properties while you're typing.
- Compile-Time Errors - By using Typescript you'll receiev errors straight into the terminal during compilation which means lesser runtime errors.
- Code Readability - With TypeScript, it’s easy to define Prop types, making the code much easier to read and use. This way we can easily document the code for other to work on.
- Easy Migration - Typescript is basically "JS + Extra Features" so we can easily write Vanilla JS inside Typescript files.
Some disadvantages of using Typescript with ReactJs are as followed :
- Missing Type Definations - Not all modules ship with Typescript support. If you come acrosss such library, you'll need to create your own type definations for it.
- Compilation Time - When using Typescript we also add an extra step of "transpilation" in the process which increases build-time for the application.
- Extra Configuration - With Typescript comes the "tsconfig" file, which is an configuration file that needs to be managed throught the project.
---------------------------------------------------------------------------------------------------------------
React Typescript Setup
1] Start Fresh Project
To generate the boilerplate code required to get started with React Typescript, execute the below command. It'll generate all the necessary files required to get started with using Typescript for React components.
By using the "--template typescript", the Create-React-App builds the app with Typescript configuration. You get the same base as the JavaScript projects, but TypeScript support has been built into the configuration.
NOTE : By default you dont need to run extra command like "tsc" to transpile your files to Javascript, CRA does that for you when you run "start".
NOTE : The ".ts" files are pure typescript files, while ".tsx" extension files are a replacement for ".js" files containing React components. TSX is similar to JSX except it's TypeScript with the JSX language extension.
2] Add Typescript to existing project
If you want to add TypeScript to the existing app, then install TypeScript and other required types.
After that rename the files to .ts or .tsx and then start the server. This will generate the tsconfig.json file automatically and you are ready to write React in TypeScript.
NOTE : In TypeScript, ".ts" files are used for regular TypeScript code that does not include JSX syntax, while ".tsx" files are used specifically for TypeScript code that includes JSX syntax for defining React components. The TypeScript compiler treats these files differently, with ".tsx" files including built-in support for JSX syntax, while ".ts" files do not.
---------------------------------------------------------------------------------------------------------------
React Typescript Types
When using React with TypeScript, we can type-safe various things like React components, Props, Event Objects, Hooks, etc. The type declarations for React and many other libraries that are used with TypeScript come from DefinitelyTyped, a community-driven project that provides type declarations for popular JavaScript libraries and tools.To use these react type declarations in a TypeScript project, you can install the @types/react package using a package manager like npm or Yarn.
Below are some common react types and their descriptions of when to use each :
React.FC: This type should be used for functional components in React. It provides type safety and enables TypeScript to check that the component is returning the right type of data.
React.Component: This type should be used for class-based components in React. It provides the same benefits asReact.FC, but for class-based components.
React.PureComponent: This type should be used for class-based components that need to be optimized for performance. It performs a shallow comparison of the component's props and state to determine if the component should be re-rendered.
React.ReactNode: This type should be used to represent the return type of a component. It's a union type of all valid JSX types and primitive types.
React.ReactElement: This type should be used to represent a single JSX element.
React.CSSProperties: This type should be used to define styles for a component.
React.FormEvent,React.MouseEvent,React.KeyboardEvent, andReact.ChangeEvent: These types should be used to define the type of event object that a handler function will receive.
React.RefObject: This type should be used to create a ref that can be attached to a component.
React.Context: This type should be used to create a context object that can be passed down to child components.
React.ProviderandReact.Consumer: These types should be used to create a provider and consumer component, respectively, for a context object.
React.Fragment: This type should be used to wrap multiple JSX elements that don't need a container element.
React.SuspenseandReact.Lazy: These types should be used for lazy loading components.
React.ErrorInfo: This type should be used to get error information forcomponentDidCatch().
React.ReactNodeArrayandReact.ReactText: These types should be used to represent arrays of JSX elements and primitive types in JSX, respectively.
---------------------------------------------------------------------------------------------------------------
Typing Component Props
In regular react we could create and pass props to the components freely and dynamically, but when using typescript we have to add types to our props before we use them inside our components. This way we get type-safety and also better autocompletion for props inside the components when writing code.
There are many ways to add types to component props, all do the same thing i.e add types to props, but differ in their syntax, some common ways are as follows :
1] Types with Interface
Define an Interface with all the default and optional component props and set their types, then just simply add it as argument type inside the component.
NOTE : To make a prop optional in the props interface, mark it with symbol ?.
As we know Interfaces can be extended, we can use this to breakdown our props into different Interfaces which extend each other's properties.
2] Types with Type-Alias
We can also use type-aliases instead of OOP interfaces to define component props. It is prefered to use Type alias for typing component props as it's more constrained then Interfaces which can be extended.
We can also pass the Props type along with the React.FC type using the brackets "<>" notation, as shown in the below example code.
Similar to how Interfaces can extend each other, we can use the "Type Intersections" to combine the properties of multiple type aliases.
3] Destructuring of Props
We can also destructure the props rather than just accessing them using the props object passed to the functional component.
or we can skip writing the Interface or Type Alias and define the prop types directly into the Functional component.
4] Default Prop Values
Before React 18,when defining the Types for component props we can make some props optional by mentioning the "?" symbol, but we can't define a default value to props like that. To add default values you can set default props on a functional component by adding a static property named defaultProps to the component function itself.
If the values for props are not provided then the default values will be used to render the components, below is an example.
In React 18 we can set the default values for the props just like in the regular reactjs without using the "defaultProps" property.
5] Children Prop (Useful :1] Click)
Children is a special prop that allows us to pass in any type of element. It could be a number, a string, a boolean, an array of elements or even another component. All the values or components defined inside the opening and closing tag of the react component will be rendered at "props.children" inside that component. When using Vanilla React we could pass in any value without defining the types beforehand.
When using Typescript with React we need to explicitly define the type for the children prop, in such cases the Union type (|) comes handy to define multiple types for a single prop. Alternatively, you can set the type of children prop to "any" so it'll behave same as it used to in regular React application without Typescript.
Example] In the below example we define the type for the special children prop.
Some common types which can be used as type for children prop :
- ReactElement
- JSX.Element
- React.ReactNode
React Types
In the above example we saw how we can add types to the component props that we are passing, in this part we'll see some useful types we can use for react components which accept other react components as their props. You can use them as types for regular props or as a return value too, but mostly you'll be using these types with the special "children" prop.
1] ReactElement
It is the most basic of the types. It represents a single child element. When typed to a prop, that prop can only accept a single react element as value. You can think of ReactElement as a primitive type of component. Other types listed below are built on top of this basic interface.
NOTE : A ReactElement Type represents an Object that has a specific Type and takes Props. In above example, Person is an ReactElement Type object.
In some cases you may want to accept multiple ReactElement objects, we can do that by mentioning the Type as an Array of ReactElements.
2] JSX.Element
The JSX.Element is an ReactElement object whose Type and Props are of type "any", so they are more or less the same. JSX.Element is a ReactElement, with the generic type for props and type being any. It exists, as various libraries can implement JSX in their own way.
NOTE : If you dont specify any Type for your react component, then it'll be considered as JSX.Element and not ReactElement.
In some cases you may want to accept multiple JSX.Element objects, we can do that by mentioning the Type as an Array of JSX.Element objects.
3] React.ReactNode
ReactNode is wider, it can be text, number, boolean, null, undefined, a portal, a ReactElement, or an array of ReactNodes. It represents anything that React can render. React node itself is a representation of the virtual DOM. So ReactNode is the set of all possible return values which can be returned by a component.
4] React.CSSProperties
Sometimes you may want to pass CSS properties as the prop value to the component, you can even type-safe the prop to accept only CSS properties as value by using the "React.CSSProperties" type.
---------------------------------------------------------------------------------------------------------------
Functional Components (Useful : 1] Click 2] Click)
In the above part we saw some special types for react functional components and their props. In this part we'll see "React.FC" or "React.FunctionComponent", which is another type we can use to type-safe our react components. This is just an alternative way to define functional components when using TS with React.
As compared to other types like ReactNode or JSX.Element, the React.FC is generally discouraged due to the following reasons :
- Implicit definition of children prop.
- Cannot use generics with it.
- The syntax is longer and confusing.
Example] When using React.FC, we define our props types inside the "<>" brackets, rest all functionality remains the same.
We can also directly destructure the props and define their types inline rather than using any interface or type defination.
Implicit children definition (Before React 18)
Before the React 18 type updates,
React.FunctionComponentprovided an implicit definition ofchildren, which was heavily debated and is one of the reasons whyReact.FCwas removed from the Create-React-App TypeScript template.
NOTE : The Implicit children definition feature is removed from React.FC in React version 18, now you need to explicitly define its type before using it.
Generic Components
Generic props are useful when you want to create a reusable data-driven component where the shape of the data varies. Reusable form, list, and table components are examples where generic props are handy. To create generic components you can use either an Interface or Type object.
Example] Creating a generic React component with TypeScript that can display a list of names and IDs, which can be of different types.
Example] Creating a generic React component with TypeScript that can display a list of strings or numbers.
NOTE : When creating generic component with single type parameter Eg - (<T>), sometimes the typescript compiler may fail to recognize it as generic and infer it as jsx element due to similar brackets. To overcome this we can extend the generic type to other types or add a comma to it at the end. Eg - (<T extends string> or <T,>)
---------------------------------------------------------------------------------------------------------------
React Hooks
In this part we'll se how to type-safe react hooks with Typescript. Their functionalities remain the same with just a simple change in their syntax.
1] useState() Hook
The useState value can be inferred from the initial value you set when you call the function, this way you can use it with any syntax change.
But when you need to initialize your state with values like null or undefined , then you need to add a Union type when you initialize the state.
When you have a complex object as the state value, you can create an interface or a type for that object as follows.
2] useEffect() & useLayoutEffect() Hooks
The useEffect()anduseLayoutEffect()both accept a callback function as first parameter we can apply type to that callback function but generally we don’t need to type the because they don’t deal with returning values. The cleanup function for theuseEffect()hook is not considered a value that can be changed either. You can write these hooks as normal.
3] useContext() Hook
The useContext hook type is usually inferred from the initial value you passed into the createContext() function as follows.
Alternatively, you can also create an Interface or Union Type that will serve as the generic for the CreateContext return value.
\
4] useRef() Hook
When using the useRef() hook we can either let Typescript infer the types or manually provide a generic/union type. The useRef hook is commonly used to reference an HTML input element we type that too.
5] useMemo() & useCallback() Hooks
The useMemo() hook returns a memoized value, so the type will be inferred from the returned value or we can manually set the type using Union.
The useCallback() hook is kind of similar to useMemo() but returns a function instead of mutable value, so it's best to rely on typescript to infer the type, or we can apply types to the callback function being passed.
6] useReducer() Hook
When using useReducer() hook with React Typescript, we need to explicitly set the types for action and state objects, If we don't, then they will be infered as "any" type. There are various ways we can type-safe action and state objects like Literal types, Type inference or with the "typeOf" keyword.
We can also use the Reducer Type with "< >" bracket notation to safe-type the reducer function, below is an example.
NOTE : If we are accepting payload inside the action object then you need to type-safe that too, below is an example.
---------------------------------------------------------------------------------------------------------------
Type HTML Events (Useful : 1] Cheatsheet)
When using Event Listeners we often pass an event object (often refered to as "e"), to the event handler function. In Typescript we have the ability to add type to that event object.
React provides many event types which we can use, some of them are as follows :
- React.MouseEvent
- React.ChangeEvent
- React.FormEvent
- React.SyntheticEvent
If you are defining the event handler function "inline", then don't necessarily have to mention the type, since Typescript can easily infer it, below is an example.
NOTE : Most HTML events types can be inferred correctly by TypeScript, so you don’t need to explicitly set the type.
But sometimes we may define our event handlers seperately, in such cases we can't rely on Typescript Inference and need to explicitly add types, below is an example.
NOTE : If you are unsure about event type then use "SyntheticEvent" which is the base event for all other events. You can also refer to documentation for specific event type for the corresponding event object.
TRICK : Event objects are of different types based on the event handler, If you are unsure about which Type to set, just write the event inline, hover over the "e" event object and if you are using VS CODE you'll get the hint, then you copy/paste the type from the hint to the event handler function.
---------------------------------------------------------------------------------------------------------------
Unsupported HTML Attributes
When it comes to HTML attributes in React-Typescript, not all attributes are supported. This is because React-Typescript provides its own syntax for handling attributes and elements in a way that is more optimized and streamlined for building interactive user interfaces.
Some of the HTML attributes that are not supported in React TypeScript include :
bgcolor: This attribute sets the background color of an element, but it's not supported in React TypeScript. Instead, you can use thestyleattribute to set the background color using CSS.
align: This attribute aligns an element, but it's not supported in React TypeScript. Instead, you can use CSS to align elements using thetext-alignorvertical-alignproperties.
alink: This attribute sets the color of active links, but it's not supported in React TypeScript. Instead, you can use CSS to set the color of active links using the:activepseudo-class.
link: This attribute sets the color of unvisited links, but it's not supported in React TypeScript. Instead, you can use CSS to set the color of unvisited links using the:linkpseudo-class.
vlink: This attribute sets the color of visited links, but it's not supported in React TypeScript. Instead, you can use CSS to set the color of visited links using the:visitedpseudo-class.
NOTE : While these attributes are not supported in React TypeScript, they are still valid HTML attributes and can be used in regular HTML documents. However, when using React TypeScript, it's generally best to use CSS to style your components and avoid using HTML attributes directly.
---------------------------------------------------------------------------------------------------------------

Comments
Post a Comment