Tips for converting API data to DTO (Data Transfer Object) using TypeScript

Here is an array of vehicles with their details.

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 defined Vehicle, Car, Plane and Train classes. My question is whether they could also be Interfaces.

The API response needs to be handled with a DTO to define the response type and facilitate casting it to the DTO type.

How can I convert the data into a typed DTO? Here are my class definitions, but I need help with the implementation.

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;
      }
    }

Answer №1

To transform the dataset, simply create a mapper for it.

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);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The React component is being rendered repeatedly

I am new to React and decided to implement some functionalities to enhance my understanding of the framework. Currently, I am working on a search feature that displays results in a table format. Each row in the table has a delete option, which triggers a p ...

Creating a modal window when a link is clicked in an MVC application

I am looking to open a Crystal Report in a pop-up window when a menu item is clicked. <%= Html.ActionLink("Display Name", "Action","Controller", new { target="blank"})%> The code above successfully opens the report, but it currently opens in a new ...

What is the best way to calculate the days, exact hours, and exact minutes between two dates using JavaScript?

I need assistance with calculating the number of days, hours, and minutes between a start date time and an end time. For example: Start Date Time = "09-06-2017 10:30" End Date Time = "10-06-2017 11:45" I am looking for the result to be 1 day, 1 ...

Changes made to code within the node_modules directory do not appear in the browser

I encountered a bug in the vuejs-datepicker project on Github, prompting me to fork the repository. However, despite making changes to the forked project, these alterations are not reflected in my main project that relies on this dependency. Here's a ...

Omit an enum item from selection when referencing the key within the Enum

Within my enum, I have defined multiple keys: export enum MyTypeEnum { one = 'one', two = 'two', three = 'three', four = 'four' } To ensure certain types must contain these keys, I use the following ...

Is it possible to transform all values in arrays to 0s in JavaScript/p5.js during the copying process?

I’m struggling with a simple code where I want to store an array of arrays containing FFT audio data. It seems like there might be a JavaScript issue because when I try to push the array into another array called spectrums, all the values inside spectr ...

When working with THREE.js in Electron, web development tools seem to vanish into thin air

Exploring electron is fairly new to me (if you know of any good documentation, please leave it in the comments) and I've encountered an issue that has left me puzzled: Everything seems fine until I load the THREE.js library. At that point, even thoug ...

The toggle function for the classList ('open') is functioning correctly and can be seen in the inspect element tool, however, the website is not displaying the associated style

How can I make the .nav show styles in .open after clicking #menu-icon? Note: I used Bootstrap to create the nav HTML <!-- logo --> <div class="logo"> <img src="assets/logo.png" alt="logo g's shop& ...

Sending information to components in Angular using Router

Should I pass data through the angular router to a component, or is it better to use a service? Currently, the component is receiving data in the following way: this.account = activatedRoute.snapshot.data.account ...

Using jQuery on the client-side to interact with a MongoDB database

Currently, I'm in the process of developing a basic example application to gain experience with using MongoDB. My goal is to create a single web page that can interact with a local MongoDB server by adding and removing content dynamically through jQue ...

Encountering an "AJAX not a function" error while using the d3/flask interface

Hey there! I'm new to the world of JavaScript and AJAX. Take a look at this d3 function I've been working on: var node = g.selectAll(".node") .data(root.descendants()) .enter().append("g") .attr("class", function(d) { return "node" + ...

Include a character in a tube using Angular

Hey everyone, I have a pipe that currently returns each word with the first letter uppercase and the rest lowercase. It also removes any non-English characters from the value. I'm trying to figure out how to add the ':' character so it will ...

I'm encountering an issue where the data in my personalDeatail model's add value is not updating automatically. Can someone please help me

I've been struggling to automatically update the data in model personalDetail.add value when adding two column data. The added data appears correctly in the input box, but it's not updating in personalDetail.add. What am I missing here? Help need ...

NPM encountered an issue that prevented it from scanning directories due to a permission denial with the error code E

Whenever I type "npm run build:prod" build:prod npm run build -- --configuration production --aot --optimization=false I encounter the following error: > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="82e4e3ece1fbafece3 ...

Struggling with loading react storybook

I am having trouble getting my storybook app to start. It is stuck in a loading state with no errors showing in the console. Can anyone help me figure out what I am doing wrong? Check out the screenshot here storybook/main.js const path = require(' ...

Excluding a common attribute from a combined type of objects can lead to issues when accessing non-common attributes (TypeScript)

In the process of developing a wrapper function, I am passing a refs property into a send function. The Event type used to construct my state machine is defined as an intersection between a base interface { refs: NodeRefs } and a union of possible event ob ...

Utilize Vue.js to selectively display or manipulate objects with a

I am currently working on a Vue.js component page that receives data from my backend. The page consists of three different filters/states that users can choose from: Unlabeled, Completed, and Skipped. Unlablled Completed Skipped My approach involves usin ...

Injectable error occurred while injecting one @Injectable() into another

I'm encountering an issue with Angular2 Dependency Injection. When attempting to inject one class into another, I am receiving the following error: Error Message: "Cannot resolve all parameters for 'ProductService'(undefined). Make sure tha ...

Angular: Modify value when checkbox is ticked

Controller: promiseObj.physical = $http.get('search?sumBoth=1&customer=' + customer).success(function(data) { $scope.servers = data; // retrieve data from JSON }); View: <tr ng-repeat="data in servers | filter: { _id: { idc: item._ ...

Ensure that the search input field is in focus whenever the showSearch state is true

Having difficulty focusing on the input field whenever the showSearch state is true. Utilizing useRef and useEffect for this purpose. When the showSearch flag changes, the useEffect hook is triggered to check if showSearch is true, and if so, it should foc ...