TypeScript Tutorial: Creating a Simple Web-Based Currency Converter

In today’s interconnected world, the need to quickly and accurately convert currencies is more prevalent than ever. Whether you’re planning a trip abroad, managing international finances, or simply curious about exchange rates, a currency converter can be an invaluable tool. This tutorial will guide you through building a simple, yet functional, web-based currency converter using TypeScript. We’ll cover everything from setting up your development environment to fetching real-time exchange rates and displaying them in a user-friendly interface. By the end of this tutorial, you’ll not only have a working currency converter but also a solid understanding of how to use TypeScript to build interactive web applications.

Why Build a Currency Converter?

Currency converters are useful for a variety of reasons. They offer a quick and easy way to:

  • Compare Prices: Understand the true cost of goods and services when shopping in different countries.
  • Manage Finances: Track and manage international transactions, investments, and savings.
  • Plan Travel: Budget and estimate expenses in foreign currencies before you travel.
  • Stay Informed: Keep up-to-date with fluctuating exchange rates and their impact on global markets.

Building your own currency converter provides a hands-on learning experience that combines front-end development with data fetching and manipulation. It’s a project that can be easily extended and customized to fit your specific needs.

Setting Up Your Development Environment

Before we dive into the code, let’s make sure you have the necessary tools installed. You’ll need:

  • Node.js and npm (or yarn): These are essential for managing project dependencies and running the development server. You can download them from nodejs.org.
  • TypeScript: We’ll use TypeScript for this project. You can install it globally using npm: npm install -g typescript
  • A Code Editor: Visual Studio Code (VS Code) is highly recommended due to its excellent TypeScript support, but you can use any editor you prefer.

Once you have these installed, create a new project directory and navigate into it using your terminal. Then, initialize a new npm project:

mkdir currency-converter
cd currency-converter
npm init -y

Next, install the necessary dependencies:

npm install typescript @types/node axios
  • typescript: The TypeScript compiler.
  • @types/node: Type definitions for Node.js, allowing TypeScript to understand Node.js modules.
  • axios: A popular library for making HTTP requests (we’ll use this to fetch exchange rates).

Now, let’s create a tsconfig.json file to configure the TypeScript compiler. Run the following command:

npx tsc --init

This will generate a tsconfig.json file in your project directory. You can customize this file to control how TypeScript compiles your code. For this project, we can use the default settings, but you might want to adjust the target (e.g., “es6” or “esnext”) and module (e.g., “commonjs” or “esnext”) options based on your needs.

Project Structure

Let’s set up a basic project structure:

currency-converter/
├── src/
│   └── index.ts
├── tsconfig.json
├── package.json
└── package-lock.json

The src/index.ts file will contain our main application code. We’ll add HTML and CSS later to create the user interface.

Fetching Exchange Rates with Axios

We’ll use a free API to get the latest exchange rates. There are several options available; for this tutorial, we’ll use ExchangeRate-API. Sign up for a free API key (if needed) and get ready to use it in your code.

Let’s write a function to fetch the exchange rates. Open src/index.ts and add the following code:

import axios from 'axios';

interface ExchangeRates {
  [currencyCode: string]: number;
}

async function getExchangeRates(baseCurrency: string): Promise {
  const apiKey = 'YOUR_API_KEY'; // Replace with your actual API key
  const apiUrl = `https://v6.exchangerate-api.com/v6/${apiKey}/latest/${baseCurrency}`;

  try {
    const response = await axios.get(apiUrl);
    if (response.data.result === 'success') {
      const rates = response.data.conversion_rates;
      return rates;
    } else {
      console.error('API Error:', response.data.error_type);
      return null;
    }
  } catch (error) {
    console.error('Error fetching exchange rates:', error);
    return null;
  }
}

Let’s break down this code:

  • We import the axios library.
  • We define an interface ExchangeRates to represent the exchange rates, using a string index signature.
  • The getExchangeRates function takes a baseCurrency (e.g., “USD”) as input.
  • We construct the API URL using your API key. Remember to replace 'YOUR_API_KEY' with your actual key.
  • We use axios.get() to make a GET request to the API.
  • We handle potential errors using a try...catch block.
  • We check if the API request was successful by verifying the result property in the response. If successful, we return the rates.
  • If there’s an error, we log the error to the console and return null.

Creating the User Interface (HTML & CSS)

Now, let’s create a simple HTML and CSS structure for our currency converter. 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>Currency Converter</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1>Currency Converter</h1>
        <div class="input-group">
            <label for="amount">Amount:</label>
            <input type="number" id="amount" placeholder="Enter amount">
        </div>
        <div class="input-group">
            <label for="fromCurrency">From:</label>
            <select id="fromCurrency">
                <!-- Currencies will be added here dynamically -->
            </select>
        </div>
        <div class="input-group">
            <label for="toCurrency">To:</label>
            <select id="toCurrency">
                <!-- Currencies will be added here dynamically -->
            </select>
        </div>
        <button id="convertButton">Convert</button>
        <div id="result"></div>
    </div>
    <script src="index.js"></script>
</body>
</html>

Next, create a style.css file in the same directory and add some basic styling:

body {
    font-family: sans-serif;
    background-color: #f4f4f4;
    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);
    width: 300px;
}

h1 {
    text-align: center;
    margin-bottom: 20px;
}

.input-group {
    margin-bottom: 15px;
}

label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
}

input[type="number"], select {
    width: 100%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
    margin-bottom: 10px;
}

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

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

#result {
    margin-top: 20px;
    font-weight: bold;
    text-align: center;
}

Implementing the Conversion Logic in TypeScript

Now, let’s write the TypeScript code that will handle the currency conversion. We’ll fetch the exchange rates, get user input, perform the calculation, and display the result. Update your src/index.ts file with the following code:

import axios from 'axios';

interface ExchangeRates {
  [currencyCode: string]: number;
}

async function getExchangeRates(baseCurrency: string): Promise<ExchangeRates | null> {
    const apiKey = 'YOUR_API_KEY'; // Replace with your actual API key
    const apiUrl = `https://v6.exchangerate-api.com/v6/${apiKey}/latest/${baseCurrency}`;

    try {
        const response = await axios.get(apiUrl);
        if (response.data.result === 'success') {
            const rates = response.data.conversion_rates;
            return rates;
        } else {
            console.error('API Error:', response.data.error_type);
            return null;
        }
    } catch (error) {
        console.error('Error fetching exchange rates:', error);
        return null;
    }
}


async function populateCurrencies() {
    const fromCurrencySelect = document.getElementById('fromCurrency') as HTMLSelectElement;
    const toCurrencySelect = document.getElementById('toCurrency') as HTMLSelectElement;

    const baseCurrency = 'USD'; // Or any default base currency
    const rates = await getExchangeRates(baseCurrency);

    if (rates) {
        const currencyCodes = Object.keys(rates);
        currencyCodes.forEach(code => {
            const optionFrom = document.createElement('option');
            optionFrom.value = code;
            optionFrom.text = code;
            fromCurrencySelect.appendChild(optionFrom);

            const optionTo = document.createElement('option');
            optionTo.value = code;
            optionTo.text = code;
            toCurrencySelect.appendChild(optionTo);
        });
    } else {
        console.error('Failed to fetch exchange rates.');
    }
}


async function convertCurrency() {
    const amountInput = document.getElementById('amount') as HTMLInputElement;
    const fromCurrencySelect = document.getElementById('fromCurrency') as HTMLSelectElement;
    const toCurrencySelect = document.getElementById('toCurrency') as HTMLSelectElement;
    const resultDiv = document.getElementById('result') as HTMLDivElement;

    const amount = parseFloat(amountInput.value);
    const fromCurrency = fromCurrencySelect.value;
    const toCurrency = toCurrencySelect.value;

    if (isNaN(amount) || amount  {
    populateCurrencies();
    const convertButton = document.getElementById('convertButton') as HTMLButtonElement;
    convertButton.addEventListener('click', convertCurrency);
});

Let’s break down this code:

  • We import the axios library and the ExchangeRates interface.
  • The getExchangeRates function remains the same as before.
  • populateCurrencies(): This function fetches the exchange rates for a base currency (e.g., USD) and populates the currency dropdowns in the HTML. It dynamically creates <option> elements for each currency.
  • convertCurrency(): This function is triggered when the “Convert” button is clicked. It retrieves the input values (amount, from currency, to currency), fetches the exchange rates, performs the conversion calculation, and displays the result in the result div.
  • We add event listeners to the “Convert” button to call the convertCurrency function when clicked.
  • The DOMContentLoaded event listener ensures that the JavaScript code runs after the HTML document has been fully loaded.

Compiling and Running the Application

Now that we’ve written the TypeScript code, we need to compile it into JavaScript that the browser can understand. Open your terminal and run the following command:

tsc

This command will use the tsconfig.json file to compile the src/index.ts file and output the compiled JavaScript file (index.js) in the same directory. If you set up your tsconfig.json correctly, the output will be in the project root.

To run the application, you can open index.html in your web browser. You may need to serve the files using a simple web server to avoid cross-origin issues when fetching data from the API. One easy way to do this is using the http-server package:

npm install -g http-server
http-server

This will start a local web server, and you can access your currency converter by opening the provided URL in your browser (usually http://localhost:8080 or similar).

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • API Key Issues: Make sure you have a valid API key and that you’ve replaced 'YOUR_API_KEY' with your actual key in the code. Double-check your API key in the API provider’s dashboard.
  • CORS Errors: If you’re encountering CORS (Cross-Origin Resource Sharing) errors, it’s likely because your browser is blocking requests from your local development server to the API. Using a web server like http-server can often resolve this. Alternatively, configure CORS settings in your browser or on the API server.
  • Incorrect File Paths: Ensure that the file paths in your HTML (e.g., <script src="index.js"></script>) are correct. The compiled JavaScript file (index.js) must be in the same directory as your HTML file.
  • Type Errors: TypeScript will highlight any type errors in your code. Pay close attention to these errors and fix them. Make sure you have the correct types for your variables and function parameters. Use type assertions (e.g., as HTMLInputElement) to help the compiler understand the types of your DOM elements.
  • Network Errors: Check your browser’s developer console for any network errors. These might indicate issues with the API request (e.g., incorrect URL, API key problems, or network connectivity issues).

Enhancements and Next Steps

This is a basic currency converter, but you can enhance it in several ways:

  • Error Handling: Implement more robust error handling to provide more informative error messages to the user. For instance, handle cases where the API is unavailable or returns an unexpected response.
  • Currency Symbols: Display currency symbols (e.g., $, €, £) alongside the converted amounts. You can use the Intl.NumberFormat API for this.
  • Currency Selection: Allow users to select a base currency.
  • Real-time Updates: Implement real-time updates of the exchange rates using WebSockets or Server-Sent Events (SSE).
  • Local Storage: Store the last used currencies and the converted amount in local storage for a better user experience.
  • More Currencies: Expand the list of supported currencies.
  • UI Improvements: Improve the user interface with better styling and layout. Consider using a CSS framework like Bootstrap or Tailwind CSS.

Key Takeaways

  • TypeScript for Web Development: You’ve learned how to use TypeScript to build a functional web application, leveraging its type safety and other features.
  • Working with APIs: You’ve learned how to fetch data from an external API (ExchangeRate-API) using the axios library.
  • DOM Manipulation: You’ve learned how to manipulate the DOM (Document Object Model) using TypeScript to create dynamic user interfaces.
  • Event Handling: You’ve learned how to handle user events (button clicks) in your TypeScript code.

FAQ

  1. Why use TypeScript for this project? TypeScript provides type safety, which helps catch errors early in the development process and makes your code more maintainable and easier to understand.
  2. Where can I get a free API key for exchange rates? You can sign up for a free API key from ExchangeRate-API or other similar providers.
  3. How can I deploy this application? You can deploy your application to a web hosting service like Netlify, Vercel, or GitHub Pages.
  4. Can I use a different API for exchange rates? Yes, you can use any API that provides exchange rate data. You’ll need to modify the code to match the API’s endpoints and response format.
  5. How do I handle different currencies? The API you choose will determine the currencies it supports. You’ll need to fetch the exchange rates for the currencies you want to support and update the dropdown options accordingly.

Building a currency converter is an excellent way to solidify your understanding of TypeScript and web development principles. As you continue to experiment and add new features, you’ll gain valuable experience in building robust and user-friendly web applications. Embrace the opportunity to learn and iterate, and you’ll be well on your way to becoming a proficient TypeScript developer. The journey of creating a functional application, from the initial setup to the final touches, provides an invaluable learning experience, fostering a deeper understanding of the development process and solidifying your skills for future endeavors. The practical application of concepts, the troubleshooting of common issues, and the continuous improvement through enhancements all contribute to a comprehensive learning experience, making each project a stepping stone towards mastery.