- Published on
How to Use TypeScript with React Components
In this article, we will explore how to effectively use TypeScript with React components.
TypeScript is a popular way to add type definitions to JavaScript code. When working with React components, TypeScript can greatly enhance code quality and helps catch errors at compile-time. In this post i am going to focus on props type validation, handling optional props, using the children prop, and enforcing return types.
Table of Contents
Props type validation with TypeScript
Props type validation means specifying the expected types of the properties that a component expects.
To add type validation for your props with TypeScript first define the type or interface that describes what props the component should accepts.
Next, in your component, you can specify the props type using the React.FC
(FunctionComponent) type. Pass in the props type as a generic argument to indicate the expected prop types.
For example, let's say we are building a component that displays list of posts.
First, let's create a Post
interface to define the structure of a blog post:
interface Post {
id: number
title: string
content: string
author: string
date: string
}
Next, we'll create a PostList
component that displays a list of blog posts:
import React from 'react'
interface PostListProps {
posts: Post[]
}
const PostList: React.FC<PostListProps> = ({ posts }) => {
return (
<div>
<h1>Blog Posts</h1>
{posts.map((post) => (
<div key={post.id}>
<h2>{post.title}</h2>
<p>{post.content}</p>
<p>Author: {post.author}</p>
<p>Date: {post.date}</p>
</div>
))}
</div>
)
}
export default PostList
As we can see from the above example in the PostListProps
interface, the prop for the PostList
component can only be an instance of Post
. In the PostList
component, we are trying to access post.title
post.content
post.author
post.date
so If we don't pass an instance of Post
in the PostList
component, TypeScript will give a compile-time error.
Now, we can use the PostList
component in our main App component by passing list of posts.
import React from 'react'
import PostList from './PostList'
const App: React.FC = () => {
const posts: Post[] = [
{
id: 1,
title: 'My First Blog Post',
content: 'Lorem ipsum dolor sit amet...',
author: 'John Doe',
date: '2022-01-01',
},
{
id: 2,
title: 'React Tips and Tricks',
content: 'Lorem ipsum dolor sit amet...',
author: 'Jane Smith',
date: '2022-01-05',
},
]
return (
<div>
<h1>My Blog</h1>
<PostList posts={posts} />
</div>
)
}
export default App
Optional Props with TypeScript
Sometimes, we might want to make certain props optional. We can achieve this by adding a ?
after the prop name in the interface definition. Here's an example
import React from 'react'
type ButtonProps = {
text: string
onClick: () => void
color?: string // Optional prop
}
const Button: React.FC<ButtonProps> = ({ text, onClick, color }) => {
return (
<button style={{ backgroundColor: color }} onClick={onClick}>
{text}
</button>
)
}
In this example, the Button
component has three props: text
, onClick
, and color
. The text
and onClick
props are required, but the color
prop is optional.
Now We can skip the color prop here's an example:
<Button text="Click Me" onClick={() => console.log('Button clicked')} />
Children Prop with TypeScript
props.children
is a special prop, automatically passed to every component, It allows you to access and render the content that is placed between the opening and closing tags when the component is rendering.
Let's slightly change the above Button
component let's change the text
prop to children
of type ReactNode
. in the previous implementation the Button
component only limited to simple text values. But now we can pass multiple elements, components.
Here's an updated version of the component:
import React, { ReactNode } from 'react'
type ButtonProps = {
children: ReactNode
onClick: () => void
color?: string // Optional prop
}
const Button: React.FC<ButtonProps> = ({ children, onClick, color }) => {
return (
<button style={{ backgroundColor: color }} onClick={onClick}>
{children}
</button>
)
}
export default Button
Now you can use an element or components as a child to indicate the message:
<Button onClick={() => console.log('Button clicked')}>
<span>Click me</span>
</Button>
<Button onClick={() => console.log('Button clicked')}>
<RiArrowRightSLine /> {* Icon component *}
</Button>
Enforced Return Type with TypeScript
TypeScript allows us to enforce the return type of our function components by specifying the type after the colon in the component definition.
const MyComponent: React.FC<MyComponentProps> = ({ name, age }): JSX.Element => {
return (
<div>
<h1>{name}</h1>
<p>{age}</p>
</div>
)
}
In this example, we explicitly specify that the component will return a JSX element.
Conclusion
Using TypeScript with react hooks provides static typing and helps catch errors early in the development process. After reading this article, I hope you can start building your react component with TypeScript in your React projects. Happy coding!