Instead of using instanceof, or checking for an existing property, we create a discriminating union type.
Type Guard is the idea that a certain property exists
Type Guarding for types
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
type Employee = { name: string; startDate: Date; } type Admin = { name: string; privilege: string []; } type UnknownEmployee = Employee | Admin; function print(emp: UnknownEmployee) { if ('privileges' in emp) { // is an Admin } if ('startDate' in emp) { // is an Employee } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Car { drive() { } } class Truck { drive() {...} loadCargo(amount: number) {. } } type Vehicle = Car | Truck; const v1 = new Car(); const v2 = new Truck(); function useVehicle (vehicle: Vehicle) { vehicle.drive(); if ('loadCargo' in vehicle) { vehicle.loadCargo(1000); } } useVehicle(v1); useVehicle(v2); |
Much better way is to use instanceof when trying to figure out what type the instance is. Because literally, instanceof is implemented to check if this particular instance is a type of something.
1 2 3 |
if (vehicle instanceof Truck) { } |
Discriminated Union
…helps with type guard.
1 2 3 4 5 6 7 8 9 10 11 |
interface Bird { flyingSpeed: number; } interface Horse { // type: 'horse' runningSpeed: number; } type Animal = Bird | Horse; |
3) discriminated Union types
can add type: ‘bird’, ‘horse’, then use switch animal.type in moveAnimal
1 2 3 4 5 6 7 8 9 |
function moveAnimal(animal: Animal) { // 1) use check guard // if ('flyingSpeed' in animal) {...} // but not good because if lots of interfaces, have to check a lot // 2) can't use instanceof because we're working with interfaces console.log('Moving with speed: ' + animal.speed); } |