TypeScript Tutorial: Creating a Simple Interactive Number Guessing Game

Have you ever wanted to build your own game? Something simple, yet engaging, that you could share with friends or add to your portfolio? In this tutorial, we’ll dive into TypeScript and create a fun, interactive number guessing game. This project is perfect for beginners to intermediate developers looking to solidify their understanding of TypeScript fundamentals, including variables, data types, conditional statements, loops, and functions. By the end of this guide, you’ll not only have a working game but also a solid foundation for tackling more complex TypeScript projects.

Why TypeScript?

Before we jump into the code, let’s talk briefly about why TypeScript is a great choice for this project (and many others). TypeScript is a superset of JavaScript that adds static typing. This means you can specify the data types of your variables, function parameters, and return values. This provides several benefits:

  • Early Error Detection: TypeScript catches type-related errors during development, before you even run your code. This saves you time and frustration by preventing runtime surprises.
  • Improved Code Readability: Type annotations make your code easier to understand, especially for larger projects. You and your team can quickly grasp the intended purpose of variables and functions.
  • Enhanced Code Completion and Refactoring: TypeScript-aware IDEs provide excellent code completion and refactoring tools, making development faster and more efficient.
  • Seamless JavaScript Integration: TypeScript compiles to JavaScript, so it runs in any browser or JavaScript environment. You can use all your favorite JavaScript libraries and frameworks.

Setting Up Your Project

Let’s get started! First, you’ll need to set up a basic TypeScript project. Here’s how:

  1. Install Node.js and npm: Make sure you have Node.js and npm (Node Package Manager) installed on your system. You can download them from the official Node.js website: https://nodejs.org/.
  2. Create a Project Directory: Open your terminal or command prompt and create a new directory for your project. For example:
mkdir number-guessing-game
cd number-guessing-game
  1. Initialize npm: Inside your project directory, initialize an npm project by running:
npm init -y
  1. Install TypeScript: Install TypeScript as a development dependency:
npm install typescript --save-dev
  1. Create a `tsconfig.json` file: This file configures the TypeScript compiler. Run the following command to generate a basic `tsconfig.json` file:
npx tsc --init

You can customize the `tsconfig.json` file to fit your project’s needs. For now, the default settings will work fine. However, you might want to uncomment and adjust the `outDir` option to specify where the compiled JavaScript files will be placed. For example:

{
  // ... other options
  "compilerOptions": {
    "outDir": "./dist",  // Output directory for compiled JavaScript files
    // ... other options
  }
}
  1. Create a TypeScript file: Create a file for your game’s code. Let’s name it `game.ts`.

Your project structure should now look something like this:

number-guessing-game/
├── node_modules/
├── package.json
├── package-lock.json
├── tsconfig.json
└── game.ts

Coding the Number Guessing Game

Now, let’s write the code for our game. Open `game.ts` in your code editor.

Step 1: Setting Up Variables

First, we’ll declare the variables we’ll need for the game. This includes the secret number, the player’s guess, the number of attempts, and any feedback messages.

// Generate a random number between 1 and 100
const secretNumber: number = Math.floor(Math.random() * 100) + 1;
let guess: number | null = null; // Initialize guess as null. We'll assign a number later.
let attempts: number = 0;
const maxAttempts: number = 10; // Maximum number of attempts allowed

// Get a reference to the element where we'll display the feedback
const feedbackElement = document.getElementById('feedback') as HTMLElement | null;
const attemptsElement = document.getElementById('attempts') as HTMLElement | null;
const guessInputElement = document.getElementById('guessInput') as HTMLInputElement | null;
const submitButton = document.getElementById('submitButton') as HTMLButtonElement | null;

Explanation:

  • `secretNumber`: This variable stores the randomly generated number that the player needs to guess. We use `Math.random()` to generate a random number between 0 and 1, multiply it by 100 to get a number between 0 and 99, and then add 1 to get a number between 1 and 100. `Math.floor()` ensures we get an integer.
  • `guess`: This variable will store the player’s guess. We initialize it to `null`.
  • `attempts`: This variable keeps track of how many guesses the player has made.
  • `maxAttempts`: Sets a limit on the number of guesses allowed.
  • `feedbackElement`, `attemptsElement`, `guessInputElement`, `submitButton`: These variables store references to HTML elements in your game’s user interface. We use `document.getElementById()` to get these elements by their IDs. The `as HTMLElement | null` is used to tell TypeScript that these elements are of type `HTMLElement` or `null`.

Step 2: Creating the Guessing Function

Next, we’ll create a function called `checkGuess()` that does the following:

  • Gets the player’s guess from the input field.
  • Checks if the guess is a valid number.
  • Compares the guess to the secret number.
  • Provides feedback to the player (e.g., “Too high!”, “Too low!”, “Correct!”).
function checkGuess(): void {
  if (!guessInputElement || !feedbackElement || !attemptsElement || !submitButton) {
    console.error('One or more of the required elements are missing.');
    return;
  }

  const guessInput = guessInputElement.value; // Get the value from the input field

  // Check if the input is a valid number
  const parsedGuess = parseInt(guessInput, 10);

  if (isNaN(parsedGuess)) {
    feedbackElement.textContent = 'Please enter a valid number.';
    return;
  }

  guess = parsedGuess;
  attempts++;

  if (attempts > maxAttempts) {
    feedbackElement.textContent = `You ran out of attempts! The number was ${secretNumber}.`;
    submitButton.disabled = true;
    return;
  }

  attemptsElement.textContent = `Attempts: ${attempts} / ${maxAttempts}`;

  if (guess === secretNumber) {
    feedbackElement.textContent = `Congratulations! You guessed the number ${secretNumber} in ${attempts} attempts.`;
    submitButton.disabled = true;
  } else if (guess < secretNumber) {
    feedbackElement.textContent = 'Too low! Try again.';
  } else {
    feedbackElement.textContent = 'Too high! Try again.';
  }
}

Explanation:

  • Element Checks: The function first checks if all required HTML elements exist, preventing errors if the game’s HTML is not set up correctly.
  • Getting the Guess: It retrieves the player’s input from the input field using `guessInputElement.value`.
  • Validating the Guess: It converts the input to a number using `parseInt()`. If the input is not a valid number (e.g., the player entered text), `isNaN()` will be true, and an error message is displayed.
  • Updating Attempts: The `attempts` counter is incremented.
  • Checking for Game Over: If the player exceeds `maxAttempts`, the game ends, and the correct number is revealed. The submit button is disabled.
  • Providing Feedback: The function compares the guess to the `secretNumber` and provides appropriate feedback (too high, too low, or correct).
  • Disabling the Button: If the guess is correct, the submit button is disabled, ending the game.

Step 3: Adding Event Listener

We need to add an event listener to the submit button so that when the player clicks it, the `checkGuess()` function is executed.


if (submitButton) {
  submitButton.addEventListener('click', checkGuess);
}

Explanation:

  • Event Listener: This code checks if `submitButton` is not null before adding the event listener. If the button exists, it listens for a “click” event. When the button is clicked, the `checkGuess` function is called.

Step 4: Creating a Reset Function

Let’s add a reset function to allow the player to start a new game.


function resetGame(): void {
  if (!feedbackElement || !attemptsElement || !guessInputElement || !submitButton) {
    console.error('One or more of the required elements are missing.');
    return;
  }

  secretNumber = Math.floor(Math.random() * 100) + 1;
  guess = null;
  attempts = 0;
  feedbackElement.textContent = '';
  attemptsElement.textContent = 'Attempts: 0 / ' + maxAttempts;
  guessInputElement.value = '';
  submitButton.disabled = false;
}

// Add a reset button or link in your HTML and attach an event listener to it.
// Example in HTML:
// <button id="resetButton">Reset Game</button>
// Example in TypeScript:
// const resetButton = document.getElementById('resetButton') as HTMLButtonElement | null;
// if (resetButton) {
//   resetButton.addEventListener('click', resetGame);
// }

Explanation:

  • Resetting the Game State: The `resetGame()` function resets all game variables to their initial states. It generates a new `secretNumber`, resets the `guess` and `attempts`, clears the feedback, resets the attempts counter display, clears the input field, and re-enables the submit button.
  • HTML and Event Listener for Reset Button: The code provides instructions and example HTML/TypeScript to create a reset button and attach an event listener to it. This allows players to easily restart the game.

Adding HTML and CSS

Now that we have the TypeScript code, let’s create the HTML and CSS for our game. This will provide the user interface for the game. Create an `index.html` file in your project directory.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Number Guessing Game</title>
  <link rel="stylesheet" href="style.css"> <!-- Link to your CSS file -->
</head>
<body>
  <div class="container">
    <h1>Number Guessing Game</h1>
    <p>I'm thinking of a number between 1 and 100. Can you guess it?</p>
    <div id="feedback"></div>
    <div id="attempts">Attempts: 0 / 10</div>
    <input type="number" id="guessInput" placeholder="Enter your guess">
    <button id="submitButton">Guess</button>
    <button id="resetButton">Reset Game</button>
  </div>
  <script src="dist/game.js"></script> <!-- Link to your compiled JavaScript file -->
</body>
</html>

Explanation:

  • Basic HTML Structure: The HTML provides the basic structure of the game, including a title, instructions, an area for feedback, an attempts counter, an input field for the player’s guess, a submit button, and a reset button.
  • CSS Link: The `<link rel=”stylesheet” href=”style.css”>` line links your HTML to a CSS file (`style.css`), which you’ll create next. This will allow you to style the game’s appearance.
  • JavaScript Link: The `<script src=”dist/game.js”></script>` line links to the compiled JavaScript file generated by the TypeScript compiler. This is where your game logic will run. Make sure that the path to your compiled JavaScript file is correct (e.g., `dist/game.js` if you set `outDir` to `dist` in your `tsconfig.json`).

Now, create a `style.css` file in your project directory to add some styling to your game.

body {
  font-family: sans-serif;
  background-color: #f0f0f0;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  margin: 0;
}

.container {
  background-color: #fff;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  text-align: center;
}

h1 {
  color: #333;
}

p {
  margin-bottom: 15px;
}

#feedback {
  margin-bottom: 15px;
  color: #e44d26; /* Example: Red for feedback */
}

#attempts {
  margin-bottom: 15px;
}

input[type="number"] {
  padding: 8px;
  font-size: 16px;
  border: 1px solid #ccc;
  border-radius: 4px;
  margin-right: 10px;
}

button {
  padding: 10px 20px;
  font-size: 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 10px;
}

button:hover {
  background-color: #3e8e41;
}

button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

Explanation:

  • Basic Styling: This CSS provides basic styling for the game, including the font, background color, container layout, heading, paragraphs, feedback, input field, and buttons.
  • Layout: The CSS centers the game content on the page.
  • Feedback Styling: The `#feedback` style sets the color for the feedback messages.
  • Button Styling: The CSS styles the buttons with a background color, text color, padding, and hover effect. The disabled state is also styled.

Compiling and Running the Game

Now that you have the HTML, CSS, and TypeScript code, you need to compile the TypeScript code into JavaScript and then run the game in your browser.

  1. Compile the TypeScript code: Open your terminal or command prompt in your project directory and run the following command:
tsc

This command will compile your `game.ts` file into a `game.js` file, which will be placed in the `dist` directory (or the directory specified in your `tsconfig.json`).

  1. Open the game in your browser: Open the `index.html` file in your web browser. You can usually do this by right-clicking on the file in your file explorer and selecting “Open with” and then choosing your browser, or by dragging the file into your browser window.
  2. Play the game: You should now be able to see the game in your browser. Enter your guesses in the input field and click the “Guess” button to play.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • Type Errors: TypeScript will report type errors during compilation. Read the error messages carefully. They usually indicate where the problem is. For example, if you try to assign a string to a number variable, TypeScript will flag this as an error. Correct the type mismatches in your code.
  • Incorrect HTML Element IDs: Make sure the IDs in your TypeScript code (e.g., `feedbackElement`, `guessInputElement`) match the IDs in your HTML file. If they don’t match, your code won’t be able to find the HTML elements, and you’ll get errors. Double-check your HTML and TypeScript code for any typos or inconsistencies.
  • Incorrect File Paths: Ensure that the file paths in your HTML (e.g., the path to the CSS file and the compiled JavaScript file) are correct. If the paths are wrong, the CSS styles won’t be applied, and the JavaScript code won’t run.
  • Uncaught TypeError: Cannot read properties of null (reading ‘value’): This is a common error that occurs when the HTML elements are not found in the DOM. This happens when the JavaScript is run before the HTML is fully loaded. To fix this, you can wrap your JavaScript code in a DOMContentLoaded event listener:
document.addEventListener('DOMContentLoaded', () => {
  // Your game setup and event listeners here
  // For example:
  const submitButton = document.getElementById('submitButton') as HTMLButtonElement | null;
  if (submitButton) {
    submitButton.addEventListener('click', checkGuess);
  }
});
  • Missing or Incorrect CSS: If your game looks unstyled, double-check the path to your `style.css` file in your HTML. Also, make sure that your CSS styles are correctly written and that there are no syntax errors.
  • Logic Errors: Carefully review your game logic for errors, such as incorrect comparisons, incorrect calculations, or incorrect game state updates. Use `console.log()` statements to debug your code and track the values of variables.

Key Takeaways

  • TypeScript Fundamentals: You’ve learned how to use variables, data types, functions, conditional statements, loops, and event listeners in TypeScript.
  • Project Setup: You’ve learned how to set up a basic TypeScript project, install the necessary dependencies, and configure the TypeScript compiler.
  • HTML and CSS Integration: You’ve learned how to create a basic HTML user interface and style it with CSS.
  • Debugging: You’ve learned how to identify and fix common errors in your code.

FAQ

Here are some frequently asked questions about this project:

  1. Can I customize the game? Absolutely! Feel free to modify the game’s logic, appearance, and features. You can change the number range, add hints, track high scores, or create different difficulty levels.
  2. How can I deploy this game online? You can deploy your game to a web hosting service like Netlify, Vercel, or GitHub Pages. These services allow you to host static websites for free. You’ll need to upload your HTML, CSS, and compiled JavaScript files.
  3. What other projects can I build with TypeScript? TypeScript is versatile. You can use it to build web applications with frameworks like React, Angular, or Vue.js, backend applications with Node.js and Express, and even mobile apps with frameworks like React Native.
  4. Where can I learn more about TypeScript? The official TypeScript documentation (https://www.typescriptlang.org/docs/) is an excellent resource. You can also find many online tutorials, courses, and books.

This tutorial provides a solid starting point for creating your own interactive games and applications with TypeScript. The principles and practices you’ve learned here can be applied to many other projects. Keep experimenting, keep learning, and don’t be afraid to try new things. The journey of a thousand lines of code begins with a single, well-typed statement.