Skip to content

scalableinternetservices/typescript_react_intro

Repository files navigation

Mini Project: Typed TODO App

Overview

Build a simple TODO application using React and TypeScript. This project will help you practice component typing, state management, and event handling in a real application.

📚 Quick Reference: TypeScript + React Cheatsheet

Learning Objectives

  • Create functional components with proper TypeScript typing
  • Manage state with useState and proper type annotations
  • Handle form events with typed event handlers
  • Practice component composition and prop passing
  • Debug TypeScript errors in a real application

Project Requirements

Core Features (Required)

  1. Define a Todo type - Create an interface for todo items
  2. Add new todos - Form to input and add todos to the list
  3. Toggle completion - Click to mark todos as complete/incomplete
  4. Display todo list - Render all todos with their status
  5. Type all components - Proper TypeScript types for props, state, and handlers

Stretch Goals (Optional)

  1. Filter todos - Show all, completed, or active todos
  2. Delete todos - Remove todos from the list
  3. Edit todos - Modify existing todo text
  4. Extract TodoItem component - Create reusable component
  5. Add input validation - Prevent empty todos

Project Structure

src/
├── components/
│   ├── TodoItem.tsx      # Individual todo component
│   ├── TodoList.tsx      # List of todos
│   └── AddTodoForm.tsx   # Form to add new todos
├── types.ts              # TypeScript type definitions
└── App.tsx               # Main application component

Getting Started

  1. Clone the repository and switch to main branch:

    git clone <repository-url>
    git checkout main
  2. Start the development server:

    npm start
  3. Check for TypeScript errors:

    npx tsc --noEmit

Step-by-Step Implementation

Step 1: Define Types

Create a Todo interface in types.ts:

export interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

Step 2: Set Up State

In App.tsx, add state for managing todos:

const [todos, setTodos] = useState<Todo[]>([]);

Step 3: Create Add Todo Function

Implement a function to add new todos:

const addTodo = (text: string) => {
  // Add implementation
};

Step 4: Create Toggle Function

Implement a function to toggle todo completion:

const toggleTodo = (id: number) => {
  // Add implementation
};

Step 5: Initialize with Dummy Data

Add some sample todos to test the application:

const [todos, setTodos] = useState<Todo[]>([
  { id: 1, text: "Learn TypeScript", completed: false },
  { id: 2, text: "Build React components", completed: true },
  { id: 3, text: "Practice with hooks", completed: false }
]);

Step 6: Create TodoItem Component

Create a component to display individual todos:

interface TodoItemProps {
  todo: Todo;
}

const TodoItem: React.FC<TodoItemProps> = ({ todo }) => {
  return (
    // Your implementation, consider using
    // <div>
    //  <p>Todo Text Goes Here</p>
    //</div>
  );
};

Add these styles to your App.css and use them to style the div an p tag

/* TodoItem Card Styles */
.todo-item {
  background: #f8f9fa;
  border: 1px solid #e9ecef;
  border-radius: 8px;
  padding: 16px;
  margin: 10px 0;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: all 0.2s ease;
}

.todo-item:hover {
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  transform: translateY(-1px);
}

.todo-text {
  font-size: 16px;
  color: #495057;
  margin: 0;
}

Display the first todo item in your App component.

Step 7: Create TodoList Component

Create a component to render all todos:

interface TodoListProps {
  todos: Todo[];
}

const TodoList: React.FC<TodoListProps> = ({ todos }) => {
  return (
    <div>
      // Iterate over todos and render TodoItems for each
    </div>
  );
};

Display the TodoList in your app

Step 8: Add Toggle Button

Add a button to each TodoItem that calls the onToggle function:

Set the text of the button depending on the completion state to "Mark as Uncompleted" or "Mark as Completed"

  <button onClick={() => call the toggle function here}>
    Set the button text here
  </button>

Add these button styles to your App.css:

.todo-button {
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  padding: 8px 16px;
  font-size: 14px;
  cursor: pointer;
  transition: background-color 0.2s ease;
  margin-left: 12px;
}

.todo-button:hover {
  background-color: #0056b3;
}

.todo-button:active {
  background-color: #004085;
  transform: translateY(1px);
}

Step 9: Show Completion Status

Modify TodoItem to modify the style and add a checkmark when completed using the styles below

Add these completion status styles to your App.css:

.todo-item.completed {
  background: #e8f5e8;
  border-color: #c3e6c3;
  opacity: 0.8;
}

.todo-item.completed .todo-text {
  text-decoration: line-through;
  color: #6c757d;
}

Step 10: Create AddTodoForm Component

Build a form component for adding new todos:

interface AddTodoFormProps {
  onAdd: (text: string) => void;
}

const AddTodoForm: React.FC<AddTodoFormProps> = ({ onAdd }) => {
  const [inputValue, setInputValue] = useState<string>('');

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    // Do something with the input to add the new todo
  };

  const handleInputChange = (...) => {
    // Handle input change here
  }

  return (
    <form className="add-todo-form" onSubmit={/* What do we do here? */}>
      <div className="form-group">
        // Use an <input> and <button> with styles below
      </div>
    </form>
  );
};

Add these form styles to your App.css:

/* AddTodoForm Styles */
.add-todo-form {
  background: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #e9ecef;
  margin-bottom: 20px;
}

.form-group {
  display: flex;
  gap: 10px;
  max-width: 500px;
  margin: 0 auto;
}

.todo-input {
  flex: 1;
  padding: 12px 16px;
  border: 2px solid #dee2e6;
  border-radius: 6px;
  font-size: 16px;
  transition: border-color 0.2s;
}

.todo-input:focus {
  outline: none;
  border-color: #007bff;
}

.add-todo-btn {
  padding: 12px 24px;
  background-color: #28a745;
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.add-todo-btn:hover {
  background-color: #218838;
}

.add-todo-btn:active {
  background-color: #1e7e34;
  transform: translateY(1px);
}

TypeScript Tips

Component Props

interface TodoItemProps {
  todo: Todo;
  onToggle: (id: number) => void;
}

const TodoItem: React.FC<TodoItemProps> = ({ todo, onToggle }) => {
  // component implementation
};

Event Handlers

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault();
  // handle form submission
};

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  // handle input change
};

State with Types

const [inputValue, setInputValue] = useState<string>('');
const [todos, setTodos] = useState<Todo[]>([]);

Common Patterns

Conditional Rendering

{todos.length === 0 ? (
  <p>No todos yet. Add one above!</p>
) : (
  <TodoList todos={todos} onToggle={toggleTodo} />
)}

Array Methods with Types

const completedTodos = todos.filter(todo => todo.completed);
const activeTodos = todos.filter(todo => !todo.completed);

Testing Your Implementation

  1. TypeScript Compilation:

    npx tsc --noEmit

    Should show no errors.

  2. Functionality Testing:

    • Add a new todo
    • Toggle todo completion
    • Verify todos persist during the session
  3. Type Safety:

    • Try passing wrong prop types
    • Verify TypeScript catches the errors

Troubleshooting

Common TypeScript Errors

"Property 'X' does not exist on type 'Y'"

  • Check that you've defined the property in your interface
  • Verify the property name spelling

"Argument of type 'X' is not assignable to parameter of type 'Y'"

  • Check the types of your function parameters
  • Ensure you're passing the correct data types

"Object is possibly 'undefined'"

  • Add optional chaining (?.) or null checks
  • Provide default values where appropriate

Getting Help

  • Use your editor's TypeScript integration
  • Run npx tsc --noEmit frequently
  • Ask your group members for help
  • Check the solution branch for reference

Success Criteria

Your TODO app is complete when:

  • ✅ All TypeScript errors are resolved
  • ✅ You can add new todos
  • ✅ You can toggle todo completion
  • ✅ All components have proper type annotations
  • ✅ The app runs without runtime errors

Next Steps

After completing the basic TODO app:

  1. Try the stretch goals
  2. Add localStorage persistence (homework)
  3. Explore the solution branch for reference
  4. Build your own TypeScript + React project

Resources

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published