In today’s globalized world, dealing with different currencies is a common occurrence. Whether you’re traveling, shopping online, or managing international finances, having a quick and reliable way to convert currencies is incredibly useful. This tutorial will guide you through building a simple currency converter using TypeScript. We’ll cover everything from setting up your project to fetching real-time exchange rates and displaying the converted amounts. By the end, you’ll have a functional application and a solid understanding of how to use TypeScript to create practical, real-world solutions.
Why TypeScript?
TypeScript, a superset of JavaScript, brings static typing to your code. This means you define the data types of your variables, function parameters, and return values. This offers several benefits:
- Early Error Detection: TypeScript catches type-related errors during development, preventing runtime surprises.
- Improved Code Readability: Type annotations make your code easier to understand and maintain.
- Enhanced Developer Experience: IDEs can provide better autocompletion, refactoring, and navigation.
- Scalability: TypeScript helps you manage larger projects more effectively.
Setting Up Your Project
Let’s get started by setting up our project. You’ll need Node.js and npm (Node Package Manager) installed on your system. If you don’t have them, download and install them from the official Node.js website.
- Create a Project Directory: Open your terminal or command prompt and create a new directory for your project:
mkdir currency-converter cd currency-converter - Initialize npm: Initialize a new npm project:
npm init -yThis creates a
package.jsonfile, which manages your project’s dependencies and scripts. - Install TypeScript: Install TypeScript globally or locally. For this tutorial, we’ll install it locally as a development dependency:
npm install typescript --save-dev - Create a TypeScript Configuration File: Generate a
tsconfig.jsonfile to configure TypeScript:npx tsc --initThis creates a
tsconfig.jsonfile with default settings. You can customize this file to control how TypeScript compiles your code. We’ll make a few adjustments shortly. - Create Source Files: Create a directory named
srcand a file namedindex.tsinside it. This is where we’ll write our TypeScript code:mkdir src touch src/index.ts
Configuring TypeScript
Open your tsconfig.json file and make the following changes to customize the compiler’s behavior. These settings will help ensure our code is compiled correctly and that we catch potential issues early.
{
"compilerOptions": {
"target": "es6", /* Specify ECMAScript target version */
"module": "commonjs", /* Specify module code generation */
"outDir": "./dist", /* Redirect output structure to the directory */
"rootDir": "./src", /* Specify the root directory of input files */
"strict": true, /* Enable all strict type-checking options. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"include": ["src/**/*"]
}
Here’s a breakdown of what these settings do:
target: "es6": Specifies that the compiled JavaScript should be compatible with ES6 (ECMAScript 2015) features.module: "commonjs": Specifies the module system to use. CommonJS is suitable for Node.js environments.outDir: "./dist": Specifies the output directory for the compiled JavaScript files.rootDir: "./src": Specifies the root directory of your TypeScript source files.strict: true: Enables strict type-checking, which is highly recommended for catching errors.esModuleInterop: true: Helps with importing modules from different module systems.skipLibCheck: true: Skips type checking of declaration files (.d.tsfiles) which can speed up compilation.forceConsistentCasingInFileNames: true: Enforces consistent casing in file names to prevent potential issues.include: ["src/**/*"]: Tells the compiler to include all TypeScript files within thesrcdirectory.
Fetching Exchange Rates
To convert currencies, we need real-time exchange rates. We’ll use a free API for this purpose. There are several options available; for this tutorial, we’ll use the ExchangeRate-API (https://www.exchangerate-api.com/). You can sign up for a free API key (which is recommended for higher rate limits), or use the API without a key, but with lower rate limits. Remember to check the API’s terms of service and rate limits.
First, let’s install the node-fetch package to make HTTP requests. This is a lightweight package that allows us to fetch data from APIs in Node.js.
npm install node-fetch
Now, let’s write the code to fetch exchange rates in src/index.ts:
import fetch from 'node-fetch';
// Replace with your API key if you have one
const API_KEY = '';
// Function to fetch exchange rates
async function getExchangeRate(fromCurrency: string, toCurrency: string): Promise {
const baseUrl = 'https://v6.exchangerate-api.com/v6';
const apiKeyPart = API_KEY ? `/${API_KEY}` : ''; // API Key is optional
const url = `${baseUrl}${apiKeyPart}/pair/${fromCurrency}/${toCurrency}`;
try {
const response = await fetch(url);
if (!response.ok) {
console.error(`API request failed with status ${response.status}`);
return null;
}
const data = await response.json();
return data.conversion_rate;
} catch (error: any) {
console.error('Error fetching exchange rate:', error.message);
return null;
}
}
// Example usage (will be called later)
async function convertCurrency(fromCurrency: string, toCurrency: string, amount: number): Promise {
const rate = await getExchangeRate(fromCurrency, toCurrency);
if (rate === null) {
return null;
}
return amount * rate;
}
Let’s break down this code:
- We import the
fetchfunction from thenode-fetchpackage. - We define an
API_KEYvariable. This is where you would put your API key from ExchangeRate-API if you have one. It’s left blank by default, allowing you to use the API without one (with rate limits). - The
getExchangeRatefunction takes two currency codes (e.g., “USD”, “EUR”) as input and returns the exchange rate as a number ornullif an error occurs. - The function constructs the API URL, including the API key if provided.
- It uses
fetchto make a GET request to the API. - It checks if the response is okay (status code 200-299). If not, it logs an error and returns
null. - It parses the JSON response and returns the
conversion_rate. - The
convertCurrencyfunction takes the from currency, to currency, and the amount to convert. It then callsgetExchangeRateto get the exchange rate and returns the converted amount.
Building the User Interface (UI)
For this tutorial, we will create a very basic command-line interface (CLI) to interact with our currency converter. This keeps the focus on the TypeScript and API interaction and avoids the complexities of building a full-fledged web or desktop UI. If you’d like to build a web-based UI, you could use HTML, CSS, and JavaScript, along with a framework like React, Angular, or Vue.js.
Let’s add some code to src/index.ts to handle user input and display the results:
import fetch from 'node-fetch';
import * as readline from 'readline';
// Replace with your API key if you have one
const API_KEY = '';
// Function to fetch exchange rates (same as before)
async function getExchangeRate(fromCurrency: string, toCurrency: string): Promise {
const baseUrl = 'https://v6.exchangerate-api.com/v6';
const apiKeyPart = API_KEY ? `/${API_KEY}` : ''; // API Key is optional
const url = `${baseUrl}${apiKeyPart}/pair/${fromCurrency}/${toCurrency}`;
try {
const response = await fetch(url);
if (!response.ok) {
console.error(`API request failed with status ${response.status}`);
return null;
}
const data = await response.json();
return data.conversion_rate;
} catch (error: any) {
console.error('Error fetching exchange rate:', error.message);
return null;
}
}
// Example usage (will be called later)
async function convertCurrency(fromCurrency: string, toCurrency: string, amount: number): Promise {
const rate = await getExchangeRate(fromCurrency, toCurrency);
if (rate === null) {
return null;
}
return amount * rate;
}
// Function to get user input
async function getUserInput(prompt: string): Promise {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(prompt, (answer) => {
rl.close();
resolve(answer);
});
});
}
// Main function to run the converter
async function main() {
try {
const fromCurrency = await getUserInput('Enter the source currency (e.g., USD): ');
const toCurrency = await getUserInput('Enter the target currency (e.g., EUR): ');
const amountStr = await getUserInput('Enter the amount to convert: ');
const amount = parseFloat(amountStr);
if (isNaN(amount)) {
console.error('Invalid amount. Please enter a number.');
return;
}
const convertedAmount = await convertCurrency(fromCurrency.toUpperCase(), toCurrency.toUpperCase(), amount);
if (convertedAmount === null) {
console.error('Could not convert the currency. Please check the currency codes and your internet connection.');
return;
}
console.log(`${amount} ${fromCurrency.toUpperCase()} is equal to ${convertedAmount.toFixed(2)} ${toCurrency.toUpperCase()}`);
} catch (error: any) {
console.error('An unexpected error occurred:', error.message);
}
}
// Run the main function
main();
Here’s a breakdown of the UI code:
- We import the
readlinemodule to handle user input from the command line. - The
getUserInputfunction prompts the user with a message and waits for their input. It usesreadline.createInterfaceto set up the input and output streams and returns a promise that resolves with the user’s answer. - The
mainfunction is the core of our application. - It calls
getUserInputto get the source currency, target currency, and the amount to convert. - It uses
parseFloatto convert the amount from a string to a number. It also validates that the input is actually a number. - It calls the
convertCurrencyfunction to perform the conversion. We convert the currency codes to uppercase to handle different input formats. - It displays the converted amount to the user, formatted to two decimal places.
- Error handling is included to catch invalid input or API errors.
- Finally, the
main()function is called to start the application.
Compiling and Running the Application
Now that we have our code, let’s compile and run it.
- Compile the TypeScript code: Open your terminal and run the following command from the root of your project directory:
npx tscThis command uses the TypeScript compiler (
tsc) to compile your.tsfiles into.jsfiles in thedistdirectory. - Run the application: Execute the compiled JavaScript file using Node.js:
node dist/index.jsThe application will prompt you to enter the source currency, target currency, and the amount to convert.
- Test the application: Enter the requested information and verify that the application correctly converts the currency. Try different currency pairs and amounts to ensure it works as expected.
Common Mistakes and How to Fix Them
Here are some common mistakes and how to avoid them:
- Incorrect API Key: If you’re using an API key, double-check that you’ve entered it correctly. Typos are a common cause of errors. Remember that if you use the API without a key, you may have rate limits.
- Incorrect Currency Codes: Make sure you’re using the correct currency codes (e.g., USD, EUR, GBP). Case sensitivity can sometimes be an issue, so it’s a good practice to convert currency codes to uppercase before using them.
- Network Issues: Ensure you have a stable internet connection. If the API request fails, the application won’t be able to fetch the exchange rate.
- Type Errors: TypeScript’s type checking can help prevent runtime errors. Review any TypeScript errors reported during compilation and fix them. For example, make sure you are passing the correct data types to functions.
- Uncaught Errors: Always handle potential errors, such as network errors or invalid API responses. Use
try...catchblocks to gracefully handle exceptions and provide informative error messages to the user. - Incorrect File Paths: Double-check the file paths when importing modules or accessing files. Ensure the paths are relative to the current file.
Key Takeaways
- TypeScript Basics: This tutorial provided a practical introduction to TypeScript, including type annotations, interfaces, and working with modules.
- API Integration: You learned how to fetch data from a REST API using
node-fetch. - User Input: You used the
readlinemodule to create a simple command-line interface for user interaction. - Error Handling: You implemented basic error handling to make your application more robust.
- Project Structure: You organized your project files and used a
tsconfig.jsonfile to configure the TypeScript compiler.
FAQ
Here are some frequently asked questions:
- Can I use a different API? Yes, you can. There are many free and paid currency exchange rate APIs available. Just make sure to adapt the code to match the API’s endpoints and data format.
- How can I improve the UI? For a more user-friendly interface, you could build a web application using HTML, CSS, and JavaScript, along with a framework like React, Angular, or Vue.js. You could also use a library like
inquirerfor a more interactive command-line interface. - How can I add more currencies? You can extend the application to support more currencies by modifying the UI to allow the user to select from a list of available currencies. You would also need to update the API calls to handle the new currencies.
- How do I handle API rate limits? If the API has rate limits (as most do), you should implement logic to handle them. This might include caching exchange rates, retrying requests, or using a different API if you exceed the limits.
- Can I store the exchange rates? Yes, you can store the exchange rates in a database or a file. This will allow you to access the exchange rates even when you do not have access to the internet, or to reduce the number of API calls. You would need to add code to read and write the exchange rates to the storage mechanism.
This tutorial provides a solid foundation for building a currency converter. You can expand upon this by adding features such as support for more currencies, historical exchange rates, and a more sophisticated user interface. The beauty of TypeScript lies in its ability to help you write cleaner, more maintainable code, making it easier to build complex applications. By understanding the core concepts presented here, you’re well-equipped to tackle more advanced TypeScript projects and build applications that solve real-world problems. The principles of type safety, modularity, and error handling are crucial for developing robust and scalable software. Applying these principles consistently will not only improve your code quality but also streamline your development process. Keep experimenting, keep learning, and explore the endless possibilities that TypeScript unlocks.
