Adding Type Annotations to Remaining DOM Functions

Let’s continue applying type annotations to the remaining DOM functions, this time for the phonetics section. The same patterns from the definitions functions apply here: return type annotations, type assertions with as, and annotating parameters with our custom types.

Refactor createPhoneticsSection Function

// Helper to clear the phonetics section
const createPhoneticsSection = (): HTMLElement => {
  const phoneticsSection: HTMLElement = document.getElementById(
    "phonetics",
  ) as HTMLElement;
  phoneticsSection.innerHTML = "";
  phoneticsSection.classList.add("flex", "flex-col", "gap-4");
  return phoneticsSection;
};

Just like clearDefinitionsSection, we use as HTMLElement to assert the return type of getElementById.

Refactor createPhoneticsHeading Function

// Helper to create the phonetics heading
const createPhoneticsHeading = (): HTMLElement => {
  const phoneticsHeading: HTMLElement = document.createElement("h1");
  phoneticsHeading.classList.add("text-2xl", "font-semibold");
  phoneticsHeading.innerText = "Phonetics";
  return phoneticsHeading;
};

Refactor createPhoneticsDiv Function

// Helper to create the phonetics div
const createPhoneticsDiv = (): HTMLElement => {
  const phoneticsDiv: HTMLElement = document.createElement("div");
  phoneticsDiv.classList.add("bg-stone-100");
  return phoneticsDiv;
};

Refactor createPhoneticElement Function

// Helper to create the phonetic element
const createPhoneticElement = (text: string): HTMLElement => {
  const phoneticText: HTMLElement = document.createElement("p");
  phoneticText.classList.add("px-4", "py-3", "text-white", "bg-stone-700");
  phoneticText.innerText = text;
  return phoneticText;
};

Refactor createAudioControl Function

// Helper to create the audio control
const createAudioControl = (): HTMLAudioElement => {
  const audioControl: HTMLAudioElement = document.createElement("audio");
  audioControl.style.width = "100%";
  audioControl.setAttribute("controls", "true");
  return audioControl;
};

Notice the return type here is HTMLAudioElement rather than the generic HTMLElement. TypeScript’s DOM type definitions include specific types for many HTML elements. When you call document.createElement("audio"), TypeScript infers the return type as HTMLAudioElement, so we can use that more specific type in our annotation.

Also notice that the original audioControl.style = "width: 100%" has been changed to audioControl.style.width = "100%". In TypeScript, the style property is a CSSStyleDeclaration object, not a string. You cannot assign a string directly to it. Instead, you set individual style properties.

Refactor createAudioSource Function

// Helper to create the audio source
const createAudioSource = (audio: string): HTMLSourceElement => {
  const source: HTMLSourceElement = document.createElement("source");
  source.setAttribute("src", audio);
  source.setAttribute("type", "audio/mpeg");
  return source;
};

Similarly, HTMLSourceElement is the specific type for <source> elements.

Refactor displayWordPhonetic Function

// Display the word phonetics
const displayWordPhonetic = (phonetics: Phonetic[] | undefined): void => {
  const phoneticsSection: HTMLElement = createPhoneticsSection();

  const phoneticsHeading: HTMLElement = createPhoneticsHeading();
  phoneticsSection.appendChild(phoneticsHeading);

  phonetics?.forEach((phonetic: Phonetic) => {
    const { text, audio } = phonetic;

    if (!text || !audio) return;

    const phoneticsDiv: HTMLElement = createPhoneticsDiv();
    phoneticsSection.appendChild(phoneticsDiv);

    const phoneticText: HTMLElement = createPhoneticElement(text);
    phoneticsDiv.appendChild(phoneticText);

    const audioControl: HTMLAudioElement = createAudioControl();
    phoneticsDiv.appendChild(audioControl);

    const source: HTMLSourceElement = createAudioSource(audio);
    audioControl.appendChild(source);

    audioControl.appendChild(
      document.createTextNode(
        "Your browser does not support the audio element.",
      ),
    );
  });
};

This follows the same pattern as displayWordDefinition: a void return type, Phonetic[] | undefined for the parameter, and optional chaining (phonetics?.forEach) to handle the case where phonetics is undefined.

Refactor displayError Function

We also have a helper function that displays an error message when a word is not found. Here is the original:

const displayError = (message) => {
  const definitionsSection = clearDefinitionsSection();
  const error = document.createElement("p");
  error.classList.add("p-4", "text-red-600", "font-semibold");
  error.innerText = message;
  definitionsSection.appendChild(error);
};

Apply the same annotations:

const displayError = (message: string): void => {
  const definitionsSection: HTMLElement = clearDefinitionsSection();
  const error: HTMLElement = document.createElement("p");
  error.classList.add("p-4", "text-red-600", "font-semibold");
  error.innerText = message;
  definitionsSection.appendChild(error);
};

Checkpoint: Commit your progress.

git add .
git commit -m "dictionary-07: Add type annotations to phonetics DOM functions"
git push