Wrapping Up the TypeScript Refactoring

Verify the Application

At this point, all of our code has been refactored to TypeScript with type annotations. Let’s verify everything works.

Start the development server:

pnpm dev

Enter a word in the input field and click “Submit.” The definitions and phonetics should display correctly. Try searching for a word that does not exist. You should see the error message.

Run the type checker to ensure there are no type errors:

pnpm type-check

And verify the production build succeeds:

pnpm build

All three should complete without errors.

An Alternative: Template Strings

Look at our display functions. They need a lot of small helper functions: one to create a heading, one for a div, one for a list item, and so on. Each helper calls document.createElement, adds classes, sets text, and returns the element. It works, but it is verbose.

An alternative approach is to use template strings to build the HTML directly. Instead of creating and assembling elements one by one, we can write the HTML structure inline and set it via innerHTML. Here is how displayWordDefinition would look:

const displayWordDefinition = (meanings: Meaning[] | undefined): void => {
  const definitionsSection = document.getElementById(
    "definitions",
  ) as HTMLElement;
  definitionsSection.innerHTML = "";

  definitionsSection.innerHTML += `
    <h1 class="text-2xl font-semibold">Definitions</h1>
  `;

  meanings?.forEach((meaning: Meaning) => {
    const definitionItems = meaning.definitions
      .map((def) => `<li>${def.definition}</li>`)
      .join("");

    definitionsSection.innerHTML += `
      <div class="bg-sky-50">
        <p class="px-4 py-2 font-semibold text-white bg-sky-600">
          ${meaning.partOfSpeech}
        </p>
        <ul class="p-2 ml-6 font-light list-disc text-sky-700">
          ${definitionItems}
        </ul>
      </div>
    `;
  });
};

And displayWordPhonetic:

const displayWordPhonetic = (phonetics: Phonetic[] | undefined): void => {
  const phoneticsSection = document.getElementById(
    "phonetics",
  ) as HTMLElement;
  phoneticsSection.innerHTML = "";
  phoneticsSection.classList.add("flex", "flex-col", "gap-4");

  phoneticsSection.innerHTML += `
    <h1 class="text-2xl font-semibold">Phonetics</h1>
  `;

  phonetics?.forEach((phonetic: Phonetic) => {
    if (!phonetic.text || !phonetic.audio) return;

    phoneticsSection.innerHTML += `
      <div class="bg-stone-100">
        <p class="px-4 py-3 text-white bg-stone-700">${phonetic.text}</p>
        <audio style="width: 100%" controls>
          <source src="${phonetic.audio}" type="audio/mpeg">
          Your browser does not support the audio element.
        </audio>
      </div>
    `;
  });
};

And displayError:

const displayError = (message: string): void => {
  const definitionsSection = document.getElementById(
    "definitions",
  ) as HTMLElement;
  definitionsSection.innerHTML = `
    <p class="p-4 text-red-600 font-semibold">${message}</p>
  `;
};

This approach has some benefits:

  • Conciseness: Far less code and no need for a dozen small helper functions.
  • Clarity: The HTML structure is immediately visible in the code.
  • Familiarity with JSX: Writing HTML inside JavaScript with template strings is very similar to JSX, which we will use extensively when we learn React.

However, there are drawbacks:

  • Security: Directly setting innerHTML can expose your application to cross-site scripting (XSS) attacks if any of the interpolated data is not properly sanitized.
  • Performance: Setting innerHTML forces the browser to reparse and reconstruct the DOM, which can be less efficient than manipulating elements directly.

When we get to React, you will see that JSX gives us both. It is as readable as template strings, and it is as safe and as efficient as manipulating the DOM directly. React’s virtual DOM handles updates efficiently, and its component model avoids the XSS risks of raw innerHTML.

Checkpoint: Commit your progress.

git add .
git commit -m "dictionary-09: Wrap up TypeScript refactoring"
git push