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.
But what about if the Car object has 0 speed?