If you have been building React applications for a while, you know that JavaScript is incredibly flexible. However, that flexibility often leads to “undefined is not a function” errors right when you least expect them.
I have spent over eight years architecting React apps, and I can tell you from experience that moving to TypeScript was the best decision for my team’s productivity. It catches bugs before you even hit ‘save.’
In this tutorial, I will show you exactly how to convert your React components to TypeScript. We will move past the basic “Hello World” and use a real-world scenario: a Sales Tax Calculator for US-based e-commerce.
Why You Should Convert to TypeScript
When I first started with React, Proptypes were the go-to for validation. While they helped, they only caught errors at runtime, which is often too late.
TypeScript provides static typing. This means your editor will tell you immediately if you are passing a string where a number should be, saving you hours of debugging.
In a large codebase, this acts as “living documentation.” You don’t have to guess what shape an object is; the type definition tells you exactly what to expect.
Method 1: Convert a Simple Functional Component
The most common task is converting a standard functional component. I usually start by changing the file extension from .jsx to .tsx.
Let’s look at a component that calculates the final price of an item, including state tax in California (currently 7.25%).
The JavaScript Version:
import React from 'react';
const SalesTaxUtility = ({ productName, price, quantity }) => {
const taxRate = 0.0725;
const total = (price * quantity) * (1 + taxRate);
return (
<div className="tax-container">
<h3>Invoice for {productName}</h3>
<p>Quantity: {quantity}</p>
<p>Total (including CA Tax): ${total.toFixed(2)}</p>
</div>
);
};
export default SalesTaxUtility;You can see the output in the screenshot below.

The TypeScript Version: To convert this, I define an interface for the props. This is the cleanest way to handle component signatures.
import React from 'react';
// I define the structure of the props here
interface SalesTaxProps {
productName: string;
price: number;
quantity: number;
}
// I use React.FC (Functional Component) to type the component
const SalesTaxUtility: React.FC<SalesTaxProps> = ({ productName, price, quantity }) => {
const taxRate: number = 0.0725;
const total: number = (price * quantity) * (1 + taxRate);
return (
<div className="tax-container" style={{ padding: '20px', border: '1px solid #ccc' }}>
<h3>Invoice for {productName}</h3>
<p>Unit Price: ${price.toFixed(2)}</p>
<p>Quantity: {quantity}</p>
<p><strong>Total (including CA Tax): ${total.toFixed(2)}</strong></p>
</div>
);
};
export default SalesTaxUtility;In this example, if someone tries to pass a string for the price, the code simply won’t compile. This level of safety is vital for financial applications.
Method 2: Handle State with the useState Hook
Managing state is where things get interesting. In many cases, TypeScript can infer the type of your state based on the initial value.
However, when dealing with complex objects like US shipping addresses, you need to be explicit.
The TypeScript Implementation:
import React, { useState } from 'react';
interface ShippingAddress {
street: string;
city: string;
state: string;
zipCode: string;
}
const AddressManager: React.FC = () => {
// I initialize the state with a ShippingAddress type
const [address, setAddress] = useState<ShippingAddress>({
street: '1600 Pennsylvania Avenue NW',
city: 'Washington',
state: 'DC',
zipCode: '20500'
});
const updateZip = (newZip: string) => {
setAddress({ ...address, zipCode: newZip });
};
return (
<div>
<h2>Shipping Department</h2>
<p>{address.street}</p>
<p>{address.city}, {address.state} {address.zipCode}</p>
<button onClick={() => updateZip('20001')}>Update to Local Hub</button>
</div>
);
};
export default AddressManager;You can see the output in the screenshot below.

Using the <ShippingAddress> syntax tells TypeScript that this state will always follow that specific structure. This prevents me from accidentally adding a field like country if it isn’t in my interface.
Method 3: Handle Form Events and Inputs
One of the trickiest parts of converting to TypeScript is typing events. I often see developers use any, but that defeats the purpose of the language.
When building a login form for a corporate portal, you want to ensure the event types are strictly defined.
The TypeScript Implementation:
import React, { useState, ChangeEvent, FormEvent } from 'react';
const EmployeeLogin: React.FC = () => {
const [email, setEmail] = useState<string>('');
// I use ChangeEvent with HTMLInputElement for the target
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
setEmail(e.target.value);
};
// I use FormEvent for the form submission
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
console.log(`Authenticating user: ${email}`);
// Logic for US-based SSO integration would go here
};
return (
<form onSubmit={handleSubmit} style={{ marginTop: '20px' }}>
<label htmlFor="email">Corporate Email:</label>
<input
id="email"
type="email"
value={email}
onChange={handleInputChange}
placeholder="user@company.us"
/>
<button type="submit">Access Secure Portal</button>
</form>
);
};
export default EmployeeLogin;You can see the output in the screenshot below.

By using ChangeEvent<HTMLInputElement>, I get full autocompletion for e.target.value. This is a huge time saver when you are building long forms.
Method 4: Convert Class-Based Components
While functional components are the standard today, you might still encounter legacy class components in older US enterprise systems.
I have found that converting these requires a slightly different approach using generic types.
The TypeScript Implementation:
import React, { Component } from 'react';
interface PayrollProps {
employeeName: string;
hourlyRate: number;
}
interface PayrollState {
hoursWorked: number;
isPaid: boolean;
}
// I pass the Props and State interfaces as generics
class PayrollCalculator extends Component<PayrollProps, PayrollState> {
constructor(props: PayrollProps) {
super(props);
this.state = {
hoursWorked: 40,
isPaid: false
};
}
processPayment = (): void => {
this.setState({ isPaid: true });
alert(`Payment processed for ${this.props.employeeName}`);
};
render() {
const grossPay = this.props.hourlyRate * this.state.hoursWorked;
return (
<div className="payroll-card">
<h2>Payroll: {this.props.employeeName}</h2>
<p>Gross Pay (Weekly): ${grossPay.toLocaleString('en-US')}</p>
<button onClick={this.processPayment} disabled={this.state.isPaid}>
{this.state.isPaid ? 'Paid' : 'Issue Paycheck'}
</button>
</div>
);
}
}
export default PayrollCalculator;In class components, Component<PayrollProps, PayrollState> ensures that both this.props and this.state are strictly typed throughout the class.
Best Practices for Migration
When I migrate a project, I don’t try to do everything at once. I start by enabling allowJs in the tsconfig.json file.
This allows me to have a mix of .js and .tsx files. I usually convert the smallest, most reused components first, like buttons or input fields.
I also avoid using any at all costs. If I am unsure of a type, I use unknown or try to define a partial interface. This keeps the integrity of the type system intact.
Useful Tips for TypeScript in React
- Use Type Shortcuts: You can use React.InputHTMLAttributes<HTMLInputElement> to quickly get all standard HTML props for an input.
- Optional Props: Use the ? symbol in your interface (e.g., middleName?: string) for fields that aren’t required.
- External Libraries: Many US-based libraries have types available via @types/ on NPM. Always check there first.
Converting your React components to TypeScript is one of the best ways to ensure your application is scalable and maintainable. It might feel like extra work initially, but the reduction in bugs is worth the effort.
In this tutorial, I have covered several ways to convert your components, from simple functional ones to state management and class-based structures.
You may also like to read:
- React Toggle Switch Component
- How to Use Await in React Components
- How to Create a Protected Route in React
- How to Use a For Loop in React Functional Components

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.