TypeScript Tutorial: Building a Simple Interactive Flight Tracker

Have you ever tracked a flight’s progress in real-time, watching it move across a map, and wondered how that seemingly magical experience is created? Behind the scenes, it involves pulling data from various sources, processing it, and displaying it in a user-friendly format. This tutorial will guide you through building a simple, interactive flight tracker using TypeScript. We’ll break down the process step-by-step, making it easy to understand even if you’re new to TypeScript or web development.

Why Build a Flight Tracker?

Creating a flight tracker is a fantastic way to learn several important concepts in web development. You’ll work with:

  • API interactions: Fetching data from external sources.
  • Data parsing: Transforming raw data into a usable format.
  • User interface (UI) design: Displaying information clearly.
  • Mapping: Visualizing data on a geographical map.

This project provides a practical application of TypeScript’s features, such as static typing, which helps catch errors early and improves code maintainability. It’s also a fun and engaging project that can be expanded upon with more features as you become more comfortable with the technologies involved.

Prerequisites

Before we begin, you’ll need the following:

  • Node.js and npm (or yarn): To manage project dependencies and run the TypeScript compiler.
  • A text editor or IDE: Such as Visual Studio Code, Sublime Text, or Atom.
  • Basic HTML and CSS knowledge: This tutorial focuses on TypeScript, but you’ll need to understand basic HTML structure and CSS styling.
  • A free API key (for flight data): We will use a free API for flight data. Get a free API key from a provider like Aviation Edge or FlightAware.

Setting Up Your Project

Let’s start by setting up our project directory and installing the necessary dependencies.

1. Create a Project Directory

Open your terminal or command prompt and create a new directory for your project:

mkdir flight-tracker
cd flight-tracker

2. Initialize npm

Initialize a new npm project:

npm init -y

This command creates a package.json file, which will manage our project’s dependencies.

3. Install TypeScript and Other Dependencies

Install TypeScript and a few other libraries that we’ll need:

npm install typescript @types/leaflet leaflet axios --save-dev
  • typescript: The TypeScript compiler.
  • @types/leaflet: Type definitions for the Leaflet library.
  • leaflet: A popular JavaScript library for interactive maps.
  • axios: A library for making HTTP requests.

4. Configure TypeScript

Create a tsconfig.json file in your project’s root directory. This file configures the TypeScript compiler. You can generate a basic one using:

npx tsc --init

This will create a tsconfig.json file with default settings. You may want to customize it. Here’s a basic configuration:

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

This configuration specifies that:

  • We’re targeting ECMAScript 5 (ES5) for compatibility.
  • We’re using CommonJS modules.
  • Compiled JavaScript files will be placed in a dist directory.
  • TypeScript source files are in the src directory.
  • Strict type checking is enabled.
  • esModuleInterop allows us to use CommonJS modules with ES module syntax.

Project Structure

Let’s create a basic project structure to keep our files organized:

flight-tracker/
├── src/
│   ├── index.ts
│   ├── styles.css
│   └── map.ts
├── dist/
├── index.html
├── package.json
├── tsconfig.json
└── ...
  • src/index.ts: The main entry point for our TypeScript code.
  • src/styles.css: Our CSS file for styling.
  • src/map.ts: Contains the map-related logic.
  • index.html: Our HTML file.
  • dist/: The directory where the compiled JavaScript will be placed.

Creating the HTML Structure

Create an index.html file in the root directory. This file will contain the basic HTML structure for our flight tracker.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Flight Tracker</title>
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
    integrity="sha512-xodZBNm5N79PjNVqGkgXzK04xK6jX69r1e+6sW6y0oXoY3j6w6f0Fw1I+3f6n4r1f2Iq9wJ8U6B0J" crossorigin=""/>
  <link rel="stylesheet" href="./src/styles.css">
</head>
<body>
  <div id="map" style="width: 100%; height: 600px;"></div>
  <script src="./dist/index.js"></script>
</body>
</html>

In this HTML:

  • We include the Leaflet CSS for map styling.
  • We link to our styles.css file for custom styles.
  • We have a div with the ID “map” where the map will be displayed.
  • We include the compiled JavaScript file (dist/index.js).

Styling the Map

Create a src/styles.css file and add some basic styles to improve the appearance of the map.

body {
  font-family: sans-serif;
  margin: 0;
  padding: 0;
}

#map {
  border: 1px solid #ccc;
}

Writing the TypeScript Code

Now, let’s write the TypeScript code to fetch flight data, display it on the map, and handle user interactions.

1. The map.ts File

Create a src/map.ts file to handle the map initialization and marker placement. This separation of concerns improves code organization and maintainability.

import L from 'leaflet';

export function initMap() {
  const map = L.map('map').setView([0, 0], 2); // Center the map at [0, 0] with zoom level 2

  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
  }).addTo(map);

  return map;
}

export function addFlightMarker(map: L.Map, latitude: number, longitude: number, flightNumber: string) {
  L.marker([latitude, longitude])
    .addTo(map)
    .bindPopup(`<b>Flight: ${flightNumber}</b>`);
}

Explanation:

  • We import the Leaflet library.
  • initMap() initializes the map, sets the initial view (center and zoom level), and adds a tile layer (the base map).
  • addFlightMarker() adds a marker to the map at the given latitude and longitude, with a popup showing the flight number.

2. The index.ts File

This is the main file where we will fetch flight data and interact with the map. Create a src/index.ts file and add the following code:

import axios from 'axios';
import { initMap, addFlightMarker } from './map';

// Replace with your API key
const apiKey = 'YOUR_API_KEY';
const apiUrl = 'https://api.aviationapi.com/v1/flights'; // Replace with the actual API endpoint

async function fetchFlights() {
  try {
    const response = await axios.get(apiUrl, { params: { api_key: apiKey } });
    const flights = response.data;
    return flights;
  } catch (error) {
    console.error('Error fetching flights:', error);
    return null;
  }
}

async function main() {
  const map = initMap();

  const flights = await fetchFlights();

  if (flights) {
    flights.forEach((flight: any) => {
      if (flight.latitude && flight.longitude && flight.flight_number) {
        addFlightMarker(map, flight.latitude, flight.longitude, flight.flight_number);
      }
    });
  }
}

main();

Explanation:

  • We import axios for making HTTP requests and our map functions from map.ts.
  • We define your API key and the API endpoint. Replace 'YOUR_API_KEY' with your actual API key. Also, make sure to replace the API endpoint with the one provided by your flight data API.
  • fetchFlights() uses axios to fetch flight data from the API. It handles potential errors.
  • main() initializes the map, fetches flight data, and then iterates through the flights, adding a marker for each flight to the map using addFlightMarker().
  • We call main() to start the process.

Compiling and Running the Application

Now, let’s compile our TypeScript code and run the application.

1. Compile the TypeScript Code

Open your terminal and navigate to your project directory. Run the following command to compile your TypeScript code:

tsc

This command will compile all TypeScript files (.ts) in your src directory and output the compiled JavaScript files (.js) and the corresponding declaration files (.d.ts) into the dist directory.

2. Run the Application

Open your index.html file in a web browser. You should see a map with markers representing the flights. If you’re not seeing anything, check your browser’s developer console for any errors, such as API key issues or data fetching problems.

Handling Errors and Common Mistakes

Debugging is a crucial part of development. Let’s look at some common issues and how to fix them:

1. API Key Issues

Problem: The map doesn’t load, and the browser console shows an error related to the API key.

Solution: Double-check your API key and ensure it’s correctly placed in the index.ts file. Also, verify that the API key is active and that your account hasn’t exceeded the API’s rate limits.

2. CORS Errors

Problem: You might see a CORS (Cross-Origin Resource Sharing) error in the console. This happens because your web page (running on your local machine) is trying to access resources from a different domain (the flight data API).

Solution: The easiest way to solve this during development is to use a CORS proxy. There are several online CORS proxies available, or you can set up your own. For example, you can use a service like https://cors-anywhere.herokuapp.com/ (use with caution, as it’s a public service). You would then modify your apiUrl to include the proxy:

const apiUrl = 'https://cors-anywhere.herokuapp.com/https://api.aviationapi.com/v1/flights';

For production, you should set up a proper backend server to make requests to the API and avoid CORS issues.

3. Data Fetching Errors

Problem: No flight data is displayed, and the console shows an error during the data fetching process (e.g., “Error fetching flights:”).

Solution:

  • Check the API endpoint: Ensure you are using the correct API endpoint provided by your flight data provider.
  • Verify the response: Inspect the response from the API using your browser’s developer tools (Network tab) to see if the data is being returned in the expected format.
  • Inspect the data: Check the structure of the data returned by the API to ensure the properties (latitude, longitude, flight_number) you are using are correct. The API might return different property names. Adjust your code accordingly.

4. Map Not Displaying

Problem: The map doesn’t appear in the browser.

Solution:

  • Check the HTML: Verify that you have included the Leaflet CSS link in your HTML, that you have a div with the ID “map”, and that the div has a specified width and height.
  • Inspect the JavaScript: Use your browser’s developer tools (Console tab) to check for JavaScript errors. Ensure that the Leaflet library is loaded correctly, and that your JavaScript is running without errors.
  • Check the CSS: Make sure your CSS is correctly linked and that the #map element has a defined width and height.

Enhancements and Next Steps

Now that you have a basic flight tracker, you can enhance it with more features:

  • Real-time updates: Use setInterval() or WebSockets to periodically fetch and update flight data in real time.
  • Flight details: Display additional information about each flight, such as origin, destination, aircraft type, and altitude. You’ll likely need to consult the API documentation to find out what data is available.
  • Search functionality: Add a search bar to allow users to search for specific flights by flight number or origin/destination airports.
  • User interface improvements: Enhance the UI with a more appealing design, different map styles, and interactive elements.
  • Clustering: If many flights are in the same area, consider using marker clustering to prevent the map from becoming cluttered.
  • Error handling: Implement more robust error handling to gracefully handle API errors or data inconsistencies.
  • Types: Create custom types to represent the flight data to improve type safety and code readability.
  • Animations: Add animations to the flight markers to simulate movement.

Key Takeaways

Here’s what you’ve learned from this tutorial:

  • How to set up a TypeScript project.
  • How to use external libraries like Leaflet and Axios.
  • How to fetch data from an API.
  • How to display data on a map.
  • How to handle common errors.

FAQ

Here are some frequently asked questions about building a flight tracker:

  1. What flight data APIs are available?

    Some popular options include Aviation Edge, FlightAware, and OpenSky Network. The best choice depends on your specific needs, such as the data you require and the pricing model.

  2. How can I handle API rate limits?

    Implement strategies like caching, request throttling, and pagination to respect the API’s rate limits. Consider using a backend server as an intermediary to manage requests and prevent your client-side code from being exposed to rate limits.

  3. Can I use this flight tracker on a mobile device?

    Yes, the flight tracker should work on mobile devices. Ensure your HTML includes the viewport meta tag (<meta name="viewport" content="width=device-width, initial-scale=1.0">) to make the map responsive.

  4. How can I deploy this flight tracker?

    You can deploy your flight tracker to various platforms, such as Netlify, Vercel, or GitHub Pages. You will need to build your TypeScript code (tsc) and then deploy the contents of the dist folder, along with your index.html and other static assets. Make sure to configure the deployment platform to serve these files correctly.

Building a flight tracker is more than just a coding exercise; it’s a gateway to understanding the complexities of real-time data visualization. You’ve now taken your first steps into the fascinating world of web-based geographical information systems (GIS). With the knowledge gained, you’re well-equipped to explore more advanced features and applications, such as integrating flight tracking with other data sources or building more sophisticated user interfaces. Continue experimenting, learning, and expanding your skill set. The possibilities are truly limitless, and the journey is just beginning.