TypeScript Tutorial: Creating a Simple Weather Application

In today’s digital landscape, accessing real-time information has become second nature. Weather updates, in particular, are something we often take for granted, but behind every temperature reading and forecast lies a complex system of data retrieval and presentation. This tutorial will guide you through building a simple weather application using TypeScript, providing you with a solid foundation in fetching data from APIs, handling asynchronous operations, and dynamically updating the user interface. This project is ideal for both beginners and intermediate developers looking to expand their TypeScript skillset and learn practical application development.

Why Build a Weather Application?

Building a weather application provides a practical and engaging way to learn several key programming concepts. It allows you to:

  • Interact with APIs: Learn how to fetch data from external sources.
  • Handle Asynchronous Operations: Understand how to manage data that takes time to retrieve.
  • Manipulate the DOM: Update the user interface dynamically based on fetched data.
  • Work with Types: Leverage TypeScript’s type system to write more robust and maintainable code.

Moreover, a weather application is a great project to showcase your skills and understanding of web development fundamentals.

Prerequisites

Before we begin, ensure you have the following installed:

  • Node.js and npm: Used for managing project dependencies and running the development server.
  • A Code Editor: Such as Visual Studio Code, Sublime Text, or Atom.
  • Basic Knowledge of HTML, CSS, and JavaScript: Familiarity with these languages is beneficial, although not strictly required.
  • TypeScript Compiler: You can install it globally using npm: npm install -g typescript

Setting Up the Project

Let’s start by setting up our project directory. Open your terminal or command prompt and execute the following commands:

mkdir weather-app
cd weather-app
npm init -y
npm install typescript --save-dev

These commands create a new directory, initialize a Node.js project, and install TypeScript as a development dependency. Next, we need to create a tsconfig.json file to configure the TypeScript compiler. Run the following command:

npx tsc --init

This command generates a tsconfig.json file in your project root. Open this file in your code editor and modify the following settings:

{
  "compilerOptions": {
    "target": "ES2015",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"]
}

These settings configure the compiler to output ES2015-compatible JavaScript, use CommonJS modules, output compiled files to a dist directory, and enable strict type checking. The include property specifies that all files within the src directory should be compiled.

Project Structure

Create the following directory structure in your project:

weather-app/
├── src/
│   ├── index.ts
│   ├── styles.css
│   └── index.html
├── package.json
├── tsconfig.json
└── dist/

The src directory will contain our TypeScript source code, HTML, and CSS files. The dist directory will hold the compiled JavaScript and other assets.

Writing the HTML

Open src/index.html and add the following HTML code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Weather App</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h1>Weather App</h1>
        <div class="search-box">
            <input type="text" id="cityInput" placeholder="Enter city name">
            <button id="searchButton">Search</button>
        </div>
        <div id="weatherInfo">
            <p id="city"></p>
            <p id="temperature"></p>
            <p id="description"></p>
            <p id="error" class="error"></p>
        </div>
    </div>
    <script src="index.js"></script>
</body>
</html>

This HTML provides the basic structure for our application, including a title, a search box for entering the city name, and elements to display the weather information. Note that we’ve included a styles.css file, which we’ll create next.

Styling with CSS

Create a file named src/styles.css and add the following CSS to style your weather app. This is a basic styling to make it look presentable. You can customize the styles to your liking.

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;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    padding: 20px;
    text-align: center;
    width: 300px;
}

h1 {
    color: #333;
}

.search-box {
    margin-bottom: 20px;
}

input[type="text"] {
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    width: 70%;
    margin-right: 10px;
}

button {
    padding: 10px 15px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

#weatherInfo {
    margin-top: 20px;
}

.error {
    color: red;
    margin-top: 10px;
}

Writing the TypeScript Code

Now, let’s write the core logic of our weather application in TypeScript. Open src/index.ts and add the following code:

// Define the API key. Replace with your own API key from OpenWeatherMap.
const apiKey = "YOUR_API_KEY";
const apiUrl = "https://api.openweathermap.org/data/2.5/weather?units=metric&q=";

// Get HTML elements
const cityInput = document.getElementById("cityInput") as HTMLInputElement;
const searchButton = document.getElementById("searchButton") as HTMLButtonElement;
const cityElement = document.getElementById("city") as HTMLParagraphElement;
const temperatureElement = document.getElementById("temperature") as HTMLParagraphElement;
const descriptionElement = document.getElementById("description") as HTMLParagraphElement;
const errorElement = document.getElementById("error") as HTMLParagraphElement;

// Function to fetch weather data
async function getWeather(city: string) {
    try {
        const response = await fetch(apiUrl + city + `&appid=${apiKey}`);
        if (!response.ok) {
            throw new Error("City not found!");
        }
        const data = await response.json();
        // Update the UI
        cityElement.textContent = data.name;
        temperatureElement.textContent = `Temperature: ${data.main.temp}°C`;
        descriptionElement.textContent = `Description: ${data.weather[0].description}`;
        errorElement.textContent = ""; // Clear any previous error
    } catch (error: any) {
        // Handle errors
        cityElement.textContent = "";
        temperatureElement.textContent = "";
        descriptionElement.textContent = "";
        errorElement.textContent = error.message;
    }
}

// Event listener for the search button
searchButton.addEventListener("click", () => {
    const city = cityInput.value;
    if (city) {
        getWeather(city);
    }
});

Let’s break down this code:

  • API Key and URL: We start by defining our API key and the base URL for the OpenWeatherMap API. Replace "YOUR_API_KEY" with your actual API key. You will need to sign up for a free API key at OpenWeatherMap.
  • HTML Element Selection: We select the HTML elements that we will interact with, using type assertions to ensure type safety. For example, document.getElementById("cityInput") as HTMLInputElement; tells TypeScript that the element with the ID “cityInput” is an HTML input element.
  • getWeather Function: This asynchronous function takes a city name as input, fetches weather data from the API, and updates the UI with the retrieved information.
  • Fetching Data: Inside the getWeather function, we use the fetch API to make a request to the OpenWeatherMap API.
  • Error Handling: We use a try...catch block to handle any errors that may occur during the API call. If the API returns an error (e.g., city not found), we display an error message in the UI.
  • Event Listener: We add an event listener to the search button. When the button is clicked, we get the city name from the input field and call the getWeather function.

Compiling and Running the Application

To compile the TypeScript code, run the following command in your terminal:

tsc

This command will compile the index.ts file and output a index.js file in the dist directory. Now, to run the application, you’ll need a simple web server. A simple way to do this is using the http-server package. If you don’t have it installed, install it globally:

npm install -g http-server

Then, navigate to the dist directory in your terminal and run the following command:

http-server

This will start a web server and provide you with a URL (usually http://localhost:8080 or similar). Open this URL in your web browser, and you should see your weather application. Enter a city name and click the search button to see the weather information.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to fix them:

  • API Key Issues: The most common issue is forgetting to replace "YOUR_API_KEY" with your actual API key. Ensure that you have a valid API key from OpenWeatherMap.
  • Incorrect API URL: Double-check the API URL and ensure it’s correct. Typos in the URL can prevent the API call from working.
  • Cross-Origin Issues: If you’re running your application locally and the API is hosted on a different domain, you might encounter cross-origin issues. You can often resolve this by using a proxy server or by configuring CORS (Cross-Origin Resource Sharing) on the API server.
  • Type Errors: TypeScript’s type checking can help catch errors early. Make sure you’re using type assertions correctly and that your code is type-safe.
  • Network Errors: Ensure you have a stable internet connection. Network issues can prevent the API call from succeeding.

Adding More Features

Here are some ideas for expanding your weather application:

  • Error Handling: Implement more robust error handling to display user-friendly error messages.
  • Unit Conversion: Add the ability to switch between Celsius and Fahrenheit.
  • Advanced Weather Details: Display additional weather information, such as humidity, wind speed, and pressure.
  • Location Search: Add an auto-complete feature for city names.
  • Background Images: Change the background image based on the weather conditions.
  • Caching: Cache API responses to reduce the number of API calls and improve performance.

Key Takeaways

  • TypeScript for Web Development: TypeScript provides static typing, improved code readability, and helps catch errors early in the development process.
  • Working with APIs: Learn how to fetch data from external APIs using the fetch API.
  • Asynchronous Operations: Understand how to handle asynchronous operations using async/await.
  • DOM Manipulation: Learn how to dynamically update the user interface based on the fetched data.

FAQ

Q: What is TypeScript?
A: TypeScript is a superset of JavaScript that adds static typing. It helps catch errors early in the development process, improves code readability, and makes it easier to maintain large codebases.

Q: Why use TypeScript for this project?
A: TypeScript helps in writing more robust and maintainable code. It also provides better tooling and autocompletion features in your code editor.

Q: How do I get an API key for OpenWeatherMap?
A: You need to sign up for a free API key on the OpenWeatherMap website. You can find the signup link on their API documentation page.

Q: What if the API call fails?
A: The getWeather function includes error handling using a try...catch block. If the API call fails, an error message is displayed in the UI.

Q: How can I deploy this application?
A: You can deploy this application using services like Netlify, Vercel, or GitHub Pages. You will need to build the project (tsc) and deploy the contents of the dist folder.

Building a weather application in TypeScript is a great way to solidify your understanding of web development principles. You’ve learned how to interact with APIs, handle asynchronous operations, and dynamically update the user interface. This foundation sets you up for tackling more complex projects. As you continue to build your skills, remember the importance of clean code, error handling, and continuous learning. Embrace the power of TypeScript to create robust and maintainable applications. Your journey into web development is just beginning, and with each project, you’ll gain valuable experience and knowledge. Keep exploring, experimenting, and pushing your boundaries. The world of web development is vast and ever-evolving, and there’s always something new to learn and discover. Enjoy the process, and happy coding!