Learn how to create functional components in React using TypeScript, define and type props interfaces, and enhance code predictability.
React is a popular JavaScript library for building user interfaces, and TypeScript enhances it by adding type safety, making your code more predictable and easier to debug. In this section, we will explore how to create functional components in React using TypeScript, define and type props interfaces, and enhance code predictability.
Functional components in React are JavaScript functions that return React elements. They are a simpler way to write components that do not require lifecycle methods or state management. Functional components are often preferred for their simplicity and ease of testing.
Let’s start by creating a simple functional component in React using TypeScript:
import React from 'react';
// Define a functional component
const Greeting: React.FC = () => {
return <h1>Hello, World!</h1>;
};
export default Greeting;
In the example above, we define a functional component called Greeting
using the React.FC
type, which stands for “Function Component.” This type provides type checking and autocomplete support for props and ensures that the component returns a valid React element.
Props (short for “properties”) are a mechanism for passing data from parent components to child components in React. To ensure type safety, we define interfaces for the props that our components expect.
Let’s create a functional component that accepts props:
import React from 'react';
// Define an interface for the props
interface GreetingProps {
name: string;
}
// Use the interface in the functional component
const Greeting: React.FC<GreetingProps> = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};
export default Greeting;
In this example, we define an interface GreetingProps
with a single property name
of type string
. We then use this interface in our functional component by specifying React.FC<GreetingProps>
. This ensures that the Greeting
component expects a name
prop of type string
.
Typed props allow us to catch errors at compile time rather than runtime, making our code more robust and easier to maintain. Let’s see another example with multiple props:
import React from 'react';
// Define an interface for the props
interface UserProps {
firstName: string;
lastName: string;
age: number;
}
// Use the interface in the functional component
const UserCard: React.FC<UserProps> = ({ firstName, lastName, age }) => {
return (
<div>
<h2>{firstName} {lastName}</h2>
<p>Age: {age}</p>
</div>
);
};
export default UserCard;
Here, the UserCard
component expects three props: firstName
, lastName
, and age
. By defining the UserProps
interface, we ensure that the component receives the correct types for each prop.
In some cases, you may want to provide default values for props or make certain props optional. TypeScript allows us to define optional props using the ?
syntax in the interface.
Let’s modify the UserCard
component to make the age
prop optional:
import React from 'react';
// Define an interface for the props
interface UserProps {
firstName: string;
lastName: string;
age?: number; // Optional prop
}
// Use the interface in the functional component
const UserCard: React.FC<UserProps> = ({ firstName, lastName, age }) => {
return (
<div>
<h2>{firstName} {lastName}</h2>
<p>Age: {age ? age : 'Unknown'}</p>
</div>
);
};
export default UserCard;
In this example, the age
prop is optional, indicated by the ?
after the property name. If age
is not provided, the component will display “Unknown.”
To provide default values for props, we can use default parameter syntax in the function signature:
import React from 'react';
// Define an interface for the props
interface UserProps {
firstName: string;
lastName: string;
age?: number;
}
// Use the interface in the functional component
const UserCard: React.FC<UserProps> = ({ firstName, lastName, age = 18 }) => {
return (
<div>
<h2>{firstName} {lastName}</h2>
<p>Age: {age}</p>
</div>
);
};
export default UserCard;
Here, we provide a default value of 18
for the age
prop. If age
is not passed, the component will use the default value.
Destructuring props in the function signature is a common pattern in React that leads to cleaner and more readable code. It allows us to directly extract the values we need from the props object.
Let’s revisit the UserCard
component with prop destructuring:
import React from 'react';
// Define an interface for the props
interface UserProps {
firstName: string;
lastName: string;
age?: number;
}
// Use the interface in the functional component
const UserCard: React.FC<UserProps> = ({ firstName, lastName, age = 18 }) => {
return (
<div>
<h2>{firstName} {lastName}</h2>
<p>Age: {age}</p>
</div>
);
};
export default UserCard;
By destructuring the firstName
, lastName
, and age
props directly in the function signature, we make the code more concise and easier to understand.
Now that we’ve covered the basics of functional components and props in React with TypeScript, try experimenting with the examples provided. Here are some suggestions:
UserCard
component to include additional props, such as email
or address
.To better understand how components and props work together in React, let’s visualize the flow using a diagram:
graph TD; ParentComponent -->|Passes Props| ChildComponent; ChildComponent -->|Receives Props| RenderedElement;
In this diagram, the ParentComponent
passes props to the ChildComponent
, which then uses these props to render elements. This flow illustrates the unidirectional data flow in React.