I’ve seen the ecosystem move from complex class components to the sleek world of functional components.
If you are using TypeScript with React, one of the first things you’ll need to master is how to properly type these functional components.
In this tutorial, I will walk you through everything you need to know about React functional component types, based on my years of experience in the trenches of web development.
Types for Functional Components
When I first started mixing TypeScript with React, I wondered if it was worth the extra effort.
The answer is a resounding yes. Using types ensures that your components receive the correct data and prevents those annoying “undefined is not a function” errors.
It makes your code self-documenting, which is a lifesaver when you’re working on a large team or returning to a project after several months.
Method 1: Use the React.FC (or React.FunctionComponent) Type
The most common way I type components is using the React.FC (which stands for Function Component) interface.
This is a generic type provided by the @types/react package. It allows you to define the shape of your props right at the component level.
Let’s look at a practical example. Imagine we are building a simple dashboard for a New York-based real estate firm to display property listings.
import React from 'react';
// Defining the shape of our props
interface PropertyCardProps {
address: string;
price: number;
city: string;
zipCode: number;
isAvailable: boolean;
}
// Using React.FC to type the component
const PropertyCard: React.FC<PropertyCardProps> = ({ address, price, city, zipCode, isAvailable }) => {
return (
<div style={{ border: '1px solid #ccc', padding: '15px', margin: '10px', borderRadius: '8px' }}>
<h2>{address}</h2>
<p>Location: {city}, NY {zipCode}</p>
<p>Price: ${price.toLocaleString()}</p>
<p>Status: {isAvailable ? 'Available for Viewing' : 'Under Contract'}</p>
</div>
);
};
export default PropertyCard;You can see the output in the screenshot below.

In this example, React.FC<PropertyCardProps> tells TypeScript that this function is a React functional component and that its props must match the PropertyCardProps interface.
One thing I like about React.FC is that it provides type checking for properties like displayName and defaultProps automatically.
Method 2: Type Props Directly (The Standard Function Way)
While React.FC is popular, many senior developers I work with prefer typing the props directly in the function signature.
This approach is often cleaner because it treats the component like any other standard JavaScript function.
Let’s say we are building a shipping calculator for an e-commerce store based in Chicago.
import React from 'react';
interface ShippingTrackerProps {
orderId: string;
carrier: 'FedEx' | 'UPS' | 'USPS';
estimatedDelivery: string;
}
// Typing the props directly in the arguments
export default function ShippingTracker({ orderId, carrier, estimatedDelivery }: ShippingTrackerProps) {
return (
<div className="tracker-container">
<h3>Track Your Package</h3>
<p><strong>Order ID:</strong> {orderId}</p>
<p><strong>Carrier:</strong> {carrier}</p>
<p><strong>Estimated Arrival:</strong> {estimatedDelivery}</p>
</div>
);
}You can see the output in the screenshot below.

I find this method particularly useful because it handles “children” more explicitly.
Unlike older versions of React.FC, this method requires you to explicitly add children to your interface if you plan to use it, which I believe leads to better type safety.
Method 3: Type Components with Optional Props
In real-world US applications, you often have data that isn’t always available.
For instance, a user profile might not always have a middle name or a secondary phone number.
In TypeScript, we use the ? symbol to mark these as optional. Let’s look at a California-based tech talent profile component.
import React from 'react';
interface DevProfileProps {
fullName: string;
role: string;
yearsOfExperience: number;
linkedInUrl?: string; // Optional prop
githubUsername?: string; // Optional prop
}
const DevProfile: React.FC<DevProfileProps> = ({ fullName, role, yearsOfExperience, linkedInUrl, githubUsername }) => {
return (
<div className="profile-card">
<h1>{fullName}</h1>
<p>Role: {role}</p>
<p>Experience: {yearsOfExperience} years</p>
{linkedInUrl && (
<a href={linkedInUrl} target="_blank" rel="noreferrer">LinkedIn Profile</a>
)}
{githubUsername && (
<p>GitHub: github.com/{githubUsername}</p>
)}
</div>
);
};
export default DevProfile;You can see the output in the screenshot below.

When you use this component, TypeScript won’t complain if you omit linkedInUrl. This is a pattern I use daily to keep components flexible.
Handle Event Types in Functional Components
A big part of typing functional components is handling events like clicks or form submissions.
I’ve seen many developers use the any type here, but that defeats the purpose of TypeScript. Instead, use the built-in React event types.
Here is a search bar example for a Texas-based grocery delivery app.
import React, { useState } from 'react';
const GrocerySearch: React.FC = () => {
const [query, setQuery] = useState<string>('');
// Typing the change event
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setQuery(event.target.value);
};
// Typing the form submission
const handleSearch = (event: React.FormEvent) => {
event.preventDefault();
console.log(`Searching for ${query} in Austin, TX...`);
};
return (
<form onSubmit={handleSearch}>
<input
type="text"
value={query}
onChange={handleInputChange}
placeholder="Search for groceries..."
/>
<button type="submit">Find Stores</button>
</form>
);
};
export default GrocerySearch;Using React.ChangeEvent<HTMLInputElement> gives you full intellisense for the event.target object, which makes coding much faster.
Best Practices I’ve Learned
After building dozens of production-ready apps, here are a few tips for typing your React components:
- Prefer Interfaces over Types: While both work, an interface is generally more extensible and offers better error messages in most IDEs.
- Export Your Interfaces: Often, you’ll need the same prop shape in a parent component or a test file. Exporting the interface makes your code more reusable.
- Avoid ‘any’: It might be tempting when you’re in a rush, but it almost always leads to bugs later.
- Use Union Types for Constants: If a prop only accepts specific strings (like ‘Small’, ‘Medium’, ‘Large’), use a union type instead of just a string.
Work with Hooks in Typed Components
Functional components rely heavily on hooks. You should type your useState and useRef hooks to ensure consistency within the component.
Here is an example of a simple tax calculator component for a freelance consultant in Seattle.
import React, { useState, useRef } from 'react';
interface TaxResult {
total: number;
taxAmount: number;
}
const SeattleTaxCalc: React.FC = () => {
// Typing useState with an interface
const [result, setResult] = useState<TaxResult | null>(null);
// Typing useRef for an HTML input
const amountRef = useRef<HTMLInputElement>(null);
const calculateTax = () => {
const amount = parseFloat(amountRef.current?.value || '0');
const waTaxRate = 0.1025; // 10.25% for Seattle
setResult({
total: amount + (amount * waTaxRate),
taxAmount: amount * waTaxRate
});
};
return (
<div className="calc-box">
<label>Enter Amount (USD): </label>
<input ref={amountRef} type="number" />
<button onClick={calculateTax}>Calculate WA Tax</button>
{result && (
<div>
<p>Tax Amount: ${result.taxAmount.toFixed(2)}</p>
<p>Total: ${result.total.toFixed(2)}</p>
</div>
)}
</div>
);
};
export default SeattleTaxCalc;In this case, useState<TaxResult | null>(null) tells TypeScript that the state starts as null but will eventually hold an object matching our TaxResult interface.
Using types for your React functional components might feel like extra work at first.
However, once you get the hang of it, you’ll find that it makes your development process much smoother and your apps much more stable.
You may also read:
- Create a React JS Table Component
- How to Create and Publish a React Component Library
- React Component Key Prop
- React Checkbox Component

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.