TypeScript Tutorial: Building a Simple Interactive JSON Formatter

In the digital age, data is king. And often, that data comes in the form of JSON (JavaScript Object Notation). Whether you’re fetching data from an API, configuring a web application, or simply storing structured information, JSON is a ubiquitous format. But raw JSON can be difficult to read and debug. That’s where a JSON formatter comes in handy. This tutorial will guide you, step-by-step, to build your own simple, interactive JSON formatter using TypeScript. You’ll learn how to parse JSON, format it for readability, and even add interactive features to enhance your development workflow. This project is perfect for beginners and intermediate developers looking to deepen their TypeScript skills and gain a practical understanding of working with JSON.

Why Build a JSON Formatter?

Raw, unformatted JSON can be a developer’s nightmare. Imagine a single line of text containing nested objects and arrays – good luck spotting an error! A JSON formatter takes that messy string and transforms it into a neatly indented, easily readable structure. This makes it far easier to:

  • Identify Errors: Properly formatted JSON highlights syntax errors, making debugging significantly faster.
  • Understand Data Structure: The indentation clearly shows the hierarchy of objects and arrays.
  • Collaborate Effectively: Formatted JSON is easier for others to read and understand.
  • Improve Development Efficiency: Spending less time deciphering JSON means more time coding.

By building your own formatter, you’ll gain a deeper appreciation for how JSON works and how to manipulate it programmatically using TypeScript. Plus, you’ll have a handy tool you can use every day!

Setting Up Your Project

Before we dive into the code, let’s set up our project environment. We’ll use Node.js and npm (Node Package Manager) to manage our dependencies and build our application. If you don’t have Node.js installed, download it from nodejs.org.

  1. Create a Project Directory: Open your terminal or command prompt and create a new directory for your project.
mkdir json-formatter-tutorial
cd json-formatter-tutorial
  1. Initialize npm: Initialize a new npm project. This will create a package.json file, which will store your project’s metadata and dependencies.
npm init -y
  1. Install TypeScript: Install TypeScript as a development dependency.
npm install --save-dev typescript
  1. Create a TypeScript Configuration File: Create a tsconfig.json file in your project root. This file tells the TypeScript compiler how to compile your code. You can generate a basic one using the TypeScript compiler itself.
npx tsc --init

This will create a tsconfig.json file preconfigured with sensible defaults. You can customize this file to fit your project’s specific needs. For this tutorial, the default settings will suffice.

  1. Create an Entry Point: Create a file named index.ts in your project root. This is where we’ll write our TypeScript code.

Writing the TypeScript Code

Now, let’s write the code for our JSON formatter. We’ll break it down into manageable steps:

1. Parsing JSON

The first step is to parse the raw JSON string. TypeScript has a built-in JSON.parse() method that handles this. We’ll create a function to take a JSON string as input and attempt to parse it.

function parseJSON(jsonString: string): any {
  try {
    return JSON.parse(jsonString);
  } catch (error) {
    console.error("Invalid JSON:", error);
    return null;
  }
}

Explanation:

  • The function parseJSON takes a jsonString (a string) as input.
  • It uses a try...catch block to handle potential errors. If the input string is not valid JSON, JSON.parse() will throw an error.
  • If the parsing is successful, the parsed JSON object is returned.
  • If an error occurs, an error message is logged to the console, and null is returned. This helps prevent the application from crashing if the user enters invalid JSON.

2. Formatting JSON

Next, we’ll create a function to format the parsed JSON object. We’ll use JSON.stringify() with the space parameter to achieve the indentation. The space parameter specifies the number of spaces to use for indentation.

function formatJSON(jsonObject: any, indent: number = 2): string {
  try {
    return JSON.stringify(jsonObject, null, indent);
  } catch (error) {
    console.error("Error formatting JSON:", error);
    return ""; // Or handle the error as needed
  }
}

Explanation:

  • The function formatJSON takes a jsonObject (the parsed JSON object) and an optional indent parameter (defaults to 2 spaces) as input.
  • It uses JSON.stringify() to convert the object back into a string.
  • The second argument, null, is a replacer function (we’re not using one here, so we pass null). The replacer allows you to customize the stringification process.
  • The third argument, indent, specifies the number of spaces for indentation. This creates the formatted output.
  • Again, a try...catch block is used to handle potential errors during the stringification process.

3. Creating the User Interface (Basic Implementation)

For this tutorial, we’ll create a very basic user interface using HTML and JavaScript (we’ll use TypeScript to write the logic). We’ll have a text area for the user to input JSON, a button to format it, and a text area to display the formatted output.

Create an index.html file in your project root with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JSON Formatter</title>
  <style>
    body {
      font-family: sans-serif;
    }
    textarea {
      width: 100%;
      height: 150px;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <h2>JSON Formatter</h2>
  <textarea id="jsonInput" placeholder="Enter JSON here"></textarea>
  <button id="formatButton">Format JSON</button>
  <textarea id="jsonOutput" readonly placeholder="Formatted JSON will appear here"></textarea>

  <script src="index.js"></script>
</body>
</html>

Explanation:

  • The HTML sets up the basic structure of the page.
  • It includes a text area for input (jsonInput), a button to trigger the formatting (formatButton), and a text area to display the output (jsonOutput).
  • The readonly attribute on the output text area prevents the user from directly editing the formatted JSON.
  • The <script src="index.js"></script> tag links to our JavaScript file (which we’ll generate from our TypeScript code).

4. Connecting the Logic to the UI

Now, let’s write the JavaScript (generated from our TypeScript) that connects our parsing and formatting functions to the user interface. Modify your index.ts file to include the following:


// Import the functions we defined earlier (or define them here if you prefer)
function parseJSON(jsonString: string): any {
  try {
    return JSON.parse(jsonString);
  } catch (error) {
    console.error("Invalid JSON:", error);
    return null;
  }
}

function formatJSON(jsonObject: any, indent: number = 2): string {
  try {
    return JSON.stringify(jsonObject, null, indent);
  } catch (error) {
    console.error("Error formatting JSON:", error);
    return ""; // Or handle the error as needed
  }
}

// Get references to the HTML elements
const jsonInput = document.getElementById('jsonInput') as HTMLTextAreaElement;
const formatButton = document.getElementById('formatButton') as HTMLButtonElement;
const jsonOutput = document.getElementById('jsonOutput') as HTMLTextAreaElement;

// Add an event listener to the button
formatButton.addEventListener('click', () => {
  const jsonString = jsonInput.value;
  const parsedJSON = parseJSON(jsonString);

  if (parsedJSON !== null) {
    const formattedJSON = formatJSON(parsedJSON);
    jsonOutput.value = formattedJSON;
  } else {
    jsonOutput.value = "Invalid JSON";
  }
});

Explanation:

  • The code first retrieves references to the HTML elements using document.getElementById(). The as HTMLTextAreaElement and as HTMLButtonElement assertions tell TypeScript the specific type of the HTML elements, enabling type checking and autocompletion.
  • An event listener is added to the formatButton. This means that when the button is clicked, the code inside the event listener function will execute.
  • Inside the event listener:
    • The value from the jsonInput text area is retrieved.
    • The parseJSON function is called to attempt to parse the input.
    • If the parsing is successful (parsedJSON is not null):
      • The formatJSON function is called to format the parsed JSON.
      • The formatted JSON is displayed in the jsonOutput text area.
    • If the parsing fails (parsedJSON is null), an “Invalid JSON” message is displayed in the jsonOutput text area.

5. Compiling and Running the Code

Now that we have our TypeScript code and HTML, we need to compile the TypeScript code into JavaScript and then run the application. Here’s how:

  1. Compile the TypeScript: Open your terminal in the project directory and run the following command to compile your TypeScript code into JavaScript. This will create an index.js file (and potentially an index.js.map file for debugging) in the same directory.
tsc
  1. Open the HTML File: Open the index.html file in your web browser. You can usually do this by double-clicking the file or by right-clicking and selecting “Open with” and choosing your browser.
  2. Test the Formatter: Enter some valid or invalid JSON into the input text area, and click the “Format JSON” button. You should see the formatted JSON (or an error message) in the output text area.

Adding More Features (Intermediate Level)

Now that you have a basic JSON formatter, let’s add some more advanced features to make it even more useful. These features will enhance the user experience and provide more control over the formatting process.

1. Indentation Control

Currently, the indentation is hardcoded to 2 spaces. Let’s allow the user to choose the indentation level. We’ll add a select dropdown to the HTML for this.

Modify your index.html to include a select dropdown:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JSON Formatter</title>
  <style>
    body {
      font-family: sans-serif;
    }
    textarea {
      width: 100%;
      height: 150px;
      margin-bottom: 10px;
    }
    select {
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <h2>JSON Formatter</h2>
  <textarea id="jsonInput" placeholder="Enter JSON here"></textarea>
  <select id="indentationSelect">
    <option value="2" selected>2 spaces</option>
    <option value="4">4 spaces</option>
    <option value="1">1 space</option>
    <option value="tab">Tab</option>
  </select>
  <button id="formatButton">Format JSON</button>
  <textarea id="jsonOutput" readonly placeholder="Formatted JSON will appear here"></textarea>

  <script src="index.js"></script>
</body>
</html>

Explanation:

  • We’ve added a <select> element with the ID indentationSelect.
  • The <option> elements provide the indentation choices (2 spaces, 4 spaces, 1 space, and Tab). Note that the value of “tab” will be handled in the TypeScript code.
  • The selected attribute on the first option makes it the default choice.

Now, update the index.ts file to handle the indentation selection:


// Import the functions we defined earlier (or define them here if you prefer)
function parseJSON(jsonString: string): any {
  try {
    return JSON.parse(jsonString);
  } catch (error) {
    console.error("Invalid JSON:", error);
    return null;
  }
}

function formatJSON(jsonObject: any, indent: number | string = 2): string {
  let indentValue: number;

  if (indent === "tab") {
    indentValue = 1; // Use 1 for tab, which JSON.stringify interprets as a tab
  } else {
    indentValue = parseInt(indent.toString(), 10); // Convert to number
  }

  try {
    return JSON.stringify(jsonObject, null, indentValue);
  } catch (error) {
    console.error("Error formatting JSON:", error);
    return ""; // Or handle the error as needed
  }
}

// Get references to the HTML elements
const jsonInput = document.getElementById('jsonInput') as HTMLTextAreaElement;
const formatButton = document.getElementById('formatButton') as HTMLButtonElement;
const jsonOutput = document.getElementById('jsonOutput') as HTMLTextAreaElement;
const indentationSelect = document.getElementById('indentationSelect') as HTMLSelectElement;

// Add an event listener to the button
formatButton.addEventListener('click', () => {
  const jsonString = jsonInput.value;
  const parsedJSON = parseJSON(jsonString);

  if (parsedJSON !== null) {
    // Get the selected indentation value
    const selectedIndent = indentationSelect.value;
    const formattedJSON = formatJSON(parsedJSON, selectedIndent);
    jsonOutput.value = formattedJSON;
  } else {
    jsonOutput.value = "Invalid JSON";
  }
});

Explanation:

  • We get a reference to the indentationSelect element.
  • Inside the formatButton event listener, we get the selected indentation value using indentationSelect.value. This value will be a string.
  • The formatJSON function is updated to accept a string or a number for the indent parameter. The code inside the formatJSON function checks if the indent parameter equals “tab”, and if so, it assigns indentValue to 1 (which will be converted to a tab character by JSON.stringify). Otherwise, it converts the string to a number using parseInt.
  • The formatJSON function is called with the selected indentation value.

Recompile your TypeScript code (tsc) and refresh your browser. Now you should be able to select different indentation levels from the dropdown.

2. Collapsible Sections (Optional, Advanced)

For very large JSON objects, it can be helpful to have collapsible sections. This allows the user to hide or show parts of the JSON to focus on specific areas. This feature requires more advanced JavaScript (not covered in this basic tutorial). However, here’s a conceptual overview of how it would work:

  • Parse the JSON with a Library: Instead of using the built-in JSON.parse() and JSON.stringify(), you would use a JavaScript library specifically designed for working with JSON and providing features like collapsible sections. Popular libraries include jsoneditor or libraries that offer similar functionality.
  • Render the JSON with Collapsible Sections: The library would provide functions to render the JSON with collapsible sections. This typically involves wrapping objects and arrays in HTML elements that can be expanded or collapsed by the user.
  • Add Event Listeners: You would add event listeners to the expand/collapse elements to handle user interactions.

Implementing collapsible sections is a more complex undertaking, but it would significantly improve the usability of your JSON formatter for large JSON files.

Common Mistakes and How to Fix Them

Here are some common mistakes developers make when working with JSON and how to avoid them:

  • Invalid JSON Syntax: This is the most common error. JSON has strict rules. Make sure you use double quotes for strings, that your objects and arrays are properly nested, and that you have the correct use of commas and colons. Use a JSON validator (like the one built into your formatter!) to check your JSON.
  • Missing Commas: Commas are essential to separate elements in arrays and key-value pairs in objects. Forgetting a comma will cause a parsing error.
  • Incorrect Use of Quotes: Only double quotes are valid for strings in JSON. Single quotes are not allowed.
  • Incorrect Data Types: Make sure your data types match what you expect. For example, if you expect a number, don’t put a string in its place.
  • Unescaped Characters: Special characters in strings (like quotes and backslashes) need to be escaped with a backslash. For example, use " for a double quote inside a string.
  • Forgetting to Handle Errors: Always include error handling (try…catch blocks) when parsing JSON to prevent your application from crashing.
  • Ignoring Indentation: While not a technical error, improperly formatted JSON is difficult to read. Use a formatter to ensure your JSON is readable.
  • Using JavaScript Objects Directly as JSON: JSON is a string format. You need to use JSON.stringify() to convert a JavaScript object into a JSON string.

Key Takeaways

  • You’ve learned how to build a basic JSON formatter using TypeScript, HTML, and JavaScript.
  • You understand the importance of formatted JSON for readability and debugging.
  • You’ve gained practical experience with JSON.parse() and JSON.stringify().
  • You know how to create a simple user interface to interact with your code.
  • You have a foundation to build upon and add more advanced features.

FAQ

Here are some frequently asked questions about JSON formatters and this tutorial:

  1. Why is my JSON not formatting correctly?
    • Double-check your JSON for syntax errors. Use a JSON validator to help.
    • Make sure you’re using double quotes for strings.
    • Ensure your objects and arrays are properly nested.
  2. Can I use this formatter in a production environment?
    • This is a simple formatter for learning purposes. It’s not designed for production use.
    • For production environments, consider using a more robust and feature-rich JSON formatter library.
  3. How can I add more features to my formatter?
    • You can add features like syntax highlighting, collapsible sections, validation, and the ability to edit the JSON directly.
    • Explore JavaScript libraries specifically designed for working with JSON, such as jsoneditor.
  4. What is the difference between JSON and JavaScript objects?
    • JSON is a string format for data interchange.
    • JavaScript objects are in-memory data structures.
    • You convert a JavaScript object to JSON using JSON.stringify(), and you convert JSON back to a JavaScript object using JSON.parse().

Building a JSON formatter is a great exercise for any developer. It reinforces fundamental concepts and provides a practical tool that can be used daily. With the skills you’ve acquired in this tutorial, you’re well on your way to becoming more proficient in TypeScript and working with data in the digital realm. Remember, practice is key. Experiment with different features, explore advanced formatting options, and continue to refine your understanding of JSON. The more you work with it, the more comfortable and efficient you will become. Keep coding, keep learning, and keep building!