Search code examples
javascripttypescriptdto

How to transform api data to DTO (Data Transfer Object) in TypeScript


I have an array of vehicles like below.

export const fetchDataFromApi = () => {
  return [
    { vehicleId: 1, vehicleType: 'car', seats: 4, wheelType: 'summer', updatedAt: new Date().toISOString },
    { vehicleId: 2, vehicleType: 'plane', seats: 200, maxAltitude: 8000, updatedAt: new Date().toISOString },
    { vehicleId: 3, vehicleType: 'train', seats: 1200, railType: 'whatever', updatedAt: new Date().toISOString },
  ];
};

I have created Vehicle, Car, Plane and Train classes. But I am not sure, those could be Interface too.

This API response should be handled with a DTO which defines the type of the response and enables casting the response into the DTO type.

So how can I transform the data into a typed DTO? Below is my class definitions but I am not sure how to implement it..

class Vehicle {
      vehicleId: number;
      vehicleType: string;
      seats: number;
      updatedAt: string;

      constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string) {
        this.vehicleId = vehicleId;
        this.vehicleType = vehicleType;
        this.seats = seats;
        this.updatedAt = updatedAt;
      }
    }

    class Car extends Vehicle {
      wheelType: string;

      constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string, wheelType: string) {
        super(vehicleId, vehicleType, seats, updatedAt);
        this.wheelType = wheelType;
      }
    }

    class Plane extends Vehicle {
      maxAltitude: number;
      constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string, maxAltitude: number) {
        super(vehicleId, vehicleType, seats, updatedAt);
        this.maxAltitude = maxAltitude;
      }
    }

    class Train extends Vehicle {
      railType: string;
      constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string, railType: string) {
        super(vehicleId, vehicleType, seats, updatedAt);
        this.railType = railType;
      }
    }

Solution

  • You just need create a mapper to transform the dataset.

    const fetchDataFromApi = (): Vehicle[] => {
        return [
          { vehicleId: 1, vehicleType: 'car', seats: 4, wheelType: 'summer', updatedAt: new Date().toISOString },
          { vehicleId: 2, vehicleType: 'plane', seats: 200, maxAltitude: 8000, updatedAt: new Date().toISOString },
          { vehicleId: 3, vehicleType: 'train', seats: 1200, railType: 'whatever', updatedAt: new Date().toISOString },
        ];
      };
      
      class Vehicle {
            vehicleId: number;
            vehicleType: string;
            seats: number;
            updatedAt: string;
      
            constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string) {
              this.vehicleId = vehicleId;
              this.vehicleType = vehicleType;
              this.seats = seats;
              this.updatedAt = updatedAt;
            }
          }
      
          class Car extends Vehicle {
            wheelType: string;
      
            constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string, wheelType: string) {
              super(vehicleId, vehicleType, seats, updatedAt);
              this.wheelType = wheelType;
            }
          }
      
          class Plane extends Vehicle {
            maxAltitude: number;
            constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string, maxAltitude: number) {
              super(vehicleId, vehicleType, seats, updatedAt);
              this.maxAltitude = maxAltitude;
            }
          }
      
          class Train extends Vehicle {
            railType: string;
            constructor(vehicleId: number, vehicleType: string, seats: number, updatedAt: string, railType: string) {
              super(vehicleId, vehicleType, seats, updatedAt);
              this.railType = railType;
            }
          }
      
      
      const vehicleMapper = (vehicle: Vehicle) => {
        const {vehicleId, vehicleType, seats, updatedAt} = vehicle;
        switch(vehicle.vehicleType) {
          case 'car':
            const {wheelType} = vehicle as Car;
            return new Car(vehicleId, vehicleType, seats, updatedAt, wheelType);
          case 'plane':
            const {maxAltitude} = vehicle as Plane;
            return new Plane(vehicleId, vehicleType, seats, updatedAt, maxAltitude);
          case 'train':
            const {railType} = vehicle as Train;
            return new Train(vehicleId, vehicleType, seats, updatedAt, railType);
          default:
            return new Vehicle(vehicleId, vehicleType, seats, updatedAt);
        }
      }
    
    
    
    const data = fetchDataFromApi();
    const vehicles = data.map(vehicleMapper);