Declaring Types for the API Response

Let’s start the refactoring by defining TypeScript types for the API response data. Once we have those types, we can add type annotations to our code and catch errors early.

To declare types for the API response data, we need to explore the structure of the API response. We can do this by making a request to the API endpoint and inspecting the JSON response. Alternatively, we can check the API documentation for type definitions or sample responses. For instance, here is the example response from the Free Dictionary API homepage.

[
  {
    word: "hello",
    phonetic: "hə'ləʊ",
    phonetics: [
      {
        text: "hə'ləʊ",
        audio:
          "//ssl.gstatic.com/dictionary/static/sounds/20200429/hello--_gb_1.mp3",
      },
      {
        text: "hɛ'ləʊ",
      },
    ],
    origin: "early 19th century: variant of earlier hollo ; related to holla.",
    meanings: [
      {
        partOfSpeech: "exclamation",
        definitions: [
          {
            definition: "used as a greeting or to begin a phone conversation.",
            example: "hello there, Katie!",
            synonyms: [],
            antonyms: [],
          },
        ],
      },
      {
        partOfSpeech: "noun",
        definitions: [
          {
            definition: "an utterance of 'hello'; a greeting.",
            example: "she was getting polite nods and hellos from people",
            synonyms: [],
            antonyms: [],
          },
        ],
      },
      {
        partOfSpeech: "verb",
        definitions: [
          {
            definition: "say or shout 'hello'.",
            example: "I pressed the phone button and helloed",
            synonyms: [],
            antonyms: [],
          },
        ],
      },
    ],
  },
];

Declaring a Type for the Definition Object

Let’s start by declaring a type for the Definition object. Add this to the top of the src/main.ts file (after the import statements):

type Definition = {
  definition: string;
  example?: string;
  synonyms?: string[];
  antonyms?: string[];
};

The Definition type represents the structure of the Definition object in the API response. It has four properties:

  • definition: A string representing the definition of the word.
  • example: A string representing an example sentence using the word. This property may be missing in some cases, so we have marked it as optional using the ? operator.
  • synonyms: An array of strings representing synonyms of the word. Like example, this may be absent, so it is also optional.
  • antonyms: An array of strings representing antonyms of the word. Also optional for the same reason.

Notice that we use the keyword type to define a new type in TypeScript. The general syntax is type TypeName = { /* type definition */ };. We define each property using the colon (:) syntax, specifying the property name followed by its type. For example, definition: string specifies that the definition property is of type string.

In TypeScript, these basic types cover most of what we need:

  • string: Represents a string value.
  • number: Represents a numeric value.
  • boolean: Represents a boolean value (true or false).
  • object: Represents a JavaScript object.

To declare an array type, we use the syntax Type[], where Type is the type of the elements in the array. For example, string[] represents an array of strings.

We often use these basic types to annotate the data type of variables, function parameters, and return values in TypeScript. For example, consider the following variable declaration:

const dictionaryAPI = "https://api.dictionaryapi.dev/api/v2/entries/en_US/";

In TypeScript, we can annotate the type of the dictionaryAPI variable as follows:

const dictionaryAPI: string =
  "https://api.dictionaryapi.dev/api/v2/entries/en_US/";

Notice how the type annotation : string is added after the variable name to specify that the dictionaryAPI variable is of type string. This is followed by the assignment operator (=) and the value of the variable.

Type annotations are optional in TypeScript, since the compiler can infer types from assigned values. However, adding explicit annotations can help catch errors early and make the code easier to read.

Declaring a Type for the Meaning Object

Next, let’s declare a type for the Meaning object:

type Meaning = {
  partOfSpeech: string;
  definitions: Definition[];
};

The Meaning type represents the structure of the Meaning object in the API response. It has two properties:

  • partOfSpeech: A string representing the part of speech of the word.
  • definitions: An array of Definition objects representing the definitions of the word.

Notice that the definitions property is an array of Definition objects. This is an example of type composition in TypeScript. We can use one type as a property of another to build up more complex structures.

Declaring a Type for the Phonetic Object

Next, let’s declare a type for the Phonetic object:

type Phonetic = {
  text?: string;
  audio?: string;
};

The Phonetic type represents the structure of the Phonetic object in the API response. It has two properties:

  • text: A string representing the phonetic text. This property may be missing in some cases, so we have marked it as optional.
  • audio: A string representing the URL to the audio file for the phonetic pronunciation. Also optional, since it may not always be provided.

Declaring a Type for the DictionaryAPIResponse Object

Finally, let’s declare a type for the DictionaryAPIResponse object, which represents the structure of the API response data:

type DictionaryAPIResponse = {
  word: string;
  phonetic?: string;
  phonetics: Phonetic[];
  origin?: string;
  meanings: Meaning[];
};

The DictionaryAPIResponse type represents the structure of the API response data. It has five properties:

  • word: A string representing the word that the response data describes.
  • phonetic: A string representing the phonetic pronunciation of the word. This property is optional since it may not always be present.
  • phonetics: An array of Phonetic objects representing the phonetic information of the word.
  • origin: A string representing the origin of the word. This property is optional.
  • meanings: An array of Meaning objects representing the meanings of the word.

With these type definitions in place, we can now use them to annotate the API response data in our code.

Checkpoint: Commit your progress.

git add .
git commit -m "dictionary-02: Declare TypeScript types for API response"
git push