Skip to content

Instantly share code, notes, and snippets.

@tjunghans
Last active March 1, 2024 07:09
Show Gist options
  • Save tjunghans/35b8a1166b4a25c3eb2177b560efd004 to your computer and use it in GitHub Desktop.
Save tjunghans/35b8a1166b4a25c3eb2177b560efd004 to your computer and use it in GitHub Desktop.
Checking the Type of an API Response in TypeScript

Checking the Type of an API Response in TypeScript

TODO: Look at Typescript User defined Type Guards

Although the title contains "TypeScript" what I'm about to show is not TypeScript specific and can and should also be done with JavaScript. The reason I am writing in the context of TypeScript is because we rely on TypeScript for type checking in most cases. An exception is when we get data from an API response such as HTTP GET and expect the data to be a certain type.

The advantage of TypeScript is that it can check variable, property, argument and function/method return types during compilation, catching errors that would possibly be thrown during run time. TypeScript cannot anticipate the shape of an API response, hence we cannot rely on TypeScripts type checking and need to do this manually.

interface Car {
  color: string;
  doors: number;
  numWheels: number;
  maxSpeed: number;
  horsepower: number;
  seats: number;
}

class Cars {
  constructor() {}
  
  cars: Car[];
  
  fetchCars() {
    fetch("/cars/").then(response => {
      this.cars = response.cars; // How do we know if `response.cars` respects the interface `Car`?
    });  
  }
}

One way to check this is to write an isA method to check for a type. In our case we would create isCar(car: any) to check if car is indeed a Car.

"If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck." See Duck typing.

interface Car {
  color: string;
  doors: number;
  wheels: number;
  speed: number;
  horsepower: number;
  seats: number;
}

class Cars {
  constructor() {}
  
  cars: Car[];
  
  fetchCars() {
    fetch("/cars/").then(response => {
      this.cars = response.cars.filter(car => {
        if (Car.isCar(car)) { return true; }
        throw new Error("TypeError", JSON.stringify(car) + " is not of type Car");
      });
    });  
  }
  
  private static isCar(car: any): boolean {
    if (!car) { return false; }
    
    return (car.color 
      && car.doors 
      && car.wheels 
      && car.speed 
      && car.horsePower 
      && car.seats);
  }
}

One could improve the conditions above by validating the type (eg. typeof car.color === "string") and value (eg. car.color !== "") of each property. A car without doors, wheels or speed make no sense. With that said, checking the value is a precaution that, in a perfect world, should not be necessary, because if the api returns an invalid Car, then the api is broken.

@dmytro-ost
Copy link

But what about if the Car object has 0 speed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment