Build Your First Interactive React Component with TypeScript
Learn to combine React and TypeScript to build robust, type-safe UI components, providing immediate practical application for aspiring frontend developers.
Building modern web interfaces with React is powerful, and adding TypeScript brings a new level of robustness and developer experience. If you're an aspiring frontend developer, understanding how to weave these two technologies together is crucial. You'll catch errors early, improve code readability, and build UIs that are easier to maintain.
This guide will walk you through creating your first interactive React component, complete with type-safe props, state, and event handling, all powered by TypeScript.
Setting Up Your Project
To get started quickly, we'll use Vite, a blazing-fast build tool that offers an excellent React + TypeScript template. Ensure you have Node.js and npm (or yarn/pnpm) installed.
Open your terminal and run the following commands:
``bash npm create vite@latest my-ts-react-app -- --template react-ts cd my-ts-react-app npm install npm run dev ``
This sets up a new React project with TypeScript, installs dependencies, and starts a development server. You should see a basic React app running in your browser.
Designing Your Interactive Component: A Simple Counter
Let's create a straightforward Counter component. It will display a number and have a button to increment it. This simple interaction will allow us to demonstrate props, state, and event handling with TypeScript.
Inside your src folder, create a new file named components/Counter.tsx. This is where our component will live.
Defining Type-Safe Props
Props (short for properties) are how data flows into your component from its parent. With TypeScript, you define an interface or type alias for your component's props, ensuring that the data passed in matches your expectations.
For our Counter, let's say we want an optional initialValue and a message to display before the count.
```typescript // src/components/Counter.tsx
import React, { useState } from 'react';
interface CounterProps { initialValue?: number; // Optional, defaults to 0 message?: string; // Optional, displays a custom message }
const Counter: React.FC<CounterProps> = ({ initialValue = 0, message = 'Current Count:' }) => { // Component logic will go here return ( <div> {/ UI will go here /} </div> ); };
export default Counter; ```
Notice React.FC<CounterProps>. FC stands for Function Component, and passing CounterProps to it tells TypeScript the expected shape of our props. If you try to pass a non-number to initialValue from a parent component, TypeScript will flag an error before your code even runs.
Managing State with useState and Types
State allows your component to manage data that changes over time and triggers re-renders. When using useState with TypeScript, you can explicitly tell it the type of your state variable.
In our Counter component, the count will be a number. We'll initialize it with initialValue.
```typescript // src/components/Counter.tsx (continued)
import React, { useState } from 'react';
interface CounterProps { initialValue?: number; message?: string; }
const Counter: React.FC<CounterProps> = ({ initialValue = 0, message = 'Current Count:' }) => { const [count, setCount] = useState<number>(initialValue); // Type explicitly set to number
return ( <div> {/ UI will go here /} </div> ); };
export default Counter; ```
By writing useState<number>(initialValue), we explicitly state that count will always be a number. TypeScript will prevent you from accidentally assigning a string or an object to count later.
Handling Interactive Events
Interaction is key to any UI. Our counter needs a button that, when clicked, increments the count. TypeScript helps here too, by providing types for event objects.
```typescript // src/components/Counter.tsx (continued)
import React, { useState } from 'react';
interface CounterProps { initialValue?: number; message?: string; }
const Counter: React.FC<CounterProps> = ({ initialValue = 0, message = 'Current Count:' }) => { const [count, setCount] = useState<number>(initialValue);
const increment = (event: React.MouseEvent<HTMLButtonElement>) => { // console.log('Button clicked!', event.currentTarget.tagName); // Optional: inspect event setCount(prevCount => prevCount + 1); };
return ( <div> <p>{message} {count}</p> <button onClick={increment}>Increment</button> </div> ); };
export default Counter; ```
The event: React.MouseEvent<HTMLButtonElement> annotation in the increment function tells TypeScript that this function expects a mouse event specifically from an HTML button element. This gives you strong type-checking and autocompletion for event properties like event.currentTarget or event.pageX.
Using Your New Component
Now that your Counter component is complete, you can use it in your App.tsx file (or any other parent component). Replace the default content in App.tsx with your Counter.
```typescript // src/App.tsx
import React from 'react'; import Counter from './components/Counter'; // Import your component import './App.css'; // Assuming you still want the default styling
function App() { return ( <div className="App"> <h1>My Interactive React App</h1> <Counter initialValue={5} message="Starting from:" /> <Counter /> {/ Uses default props /} </div> ); }
export default App; ```
Save your files, and your browser should automatically update, displaying two counter components, one starting at 5 with a custom message, and another at 0 with the default message.
Why TypeScript Matters for Frontend Developers
What we've built is a small component, but the principles scale. TypeScript might seem like an extra step, but it's an investment that pays off dramatically, especially in larger applications or team environments. It transforms potential runtime errors into compile-time warnings, making your debugging process far more efficient.
This proactive approach to error detection, combined with React's component-based architecture, empowers you to build robust, predictable, and scalable user interfaces. It's a fundamental skill for any developer aiming to build professional-grade web applications.
Eager to dive deeper into programming, web development, or software engineering principles? Tully Courses offers a variety of paths to sharpen your skills. Explore courses like Which Programming Language Should You Learn First? to solidify your foundational knowledge, or jump into advanced topics with Full-Stack Web Development with Node.js and Express. For a broader understanding of building robust systems, consider Software Engineering Craft: Code, Architecture, and Collaboration.
Ready to build more? Tully has 47 public courses available across various domains, including 23 in programming alone. Many learners on Tully choose web development as a key area, reflecting its importance in today's tech landscape.
---
Start Building on Tully
This is just a taste of what you can create. On Tully, you learn by doing, with short lessons, applied checks, and honest feedback. If you're ready to build more robust web applications, explore our web development topic hub or generate your next learning path on Tully today!
Start learning on Tully Courses — learn anything by doing it.