简体   繁体   中英

Typescript convert data from API into specific type

I need only few properties from the received object. Is it possible to map through received data and remove unnecessary properties using Typescript interface?

Example of data:

[
  0: {
    "original_language" : "en",
    "title" : "The First Title",
    "original_title" : "The First Original Title",
    "overview": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ac suscipit nulla.",
    "release_date": "2022-05-04",
    "popularity": 9411.64
  },
  1: {
    "original_language" : "en",
    "title" : "The Second Title",
    "original_title" : "The Second Original Title",
    "overview": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ac suscipit nulla.",
    "release_date": "2022-05-04",
    "popularity": 9411.64
  },
  2: {
    "original_language" : "es",
    "title" : "The Third Title",
    "original_title" : "The Third Original Title",
    "overview": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ac suscipit nulla.",
    "release_date": "2022-05-04",
    "popularity": 9411.64
  }
]

Desired object properties (Typescript Interface):

interface IMovie {
  overview: string,
  release_date: Date,
  title: string
}

My attepmt to write mapper function :

const movieMapper = (movies: []): [IMovie] => {
  return movies.map(movie => <IMovie>movie);
}

Your return type is a tuple, not an array.

You can use object destructuring to pick the fields and map to a new object.

const movieMapper = (movies: any[]): IMovie[] => {
    return movies.map(({overview, release_date, title}) => ({ overview, release_date, title}));
}

console.log(movieMapper(movies))

You can have a two interfaces: for actual api response array items and desire items:

interface MovieFull {
  original_language: string
  title: string
  original_title: string
  overview: string
  release_date: Date
  popularity: number
}

type Movie = Pick<MovieFull, 'overview' | 'release_date', 'title'>

You can have a Movie as a independent type, but it's rather to be dependent from original one so in case the MovieFull will change, Movie will also change.

Next you can perform mapping:

const movieMapper = (movies: MovieFull[]): Movie[] => {
  return movies.map(movie => ({
    overview: movie.overview,
    release_date: movie.release_date,
    title: movie.title,
  }));
}
// or, using decostruction
const movieMapper = (movies: MovieFull[]): Movie[] => {
  return movies.map(({ overview, release_date, title }) => ({ overview, release_date, title }));
}

Using io-ts you could write this codec:

// Codec file
import * as t from 'io-ts'

export const movieCodec = t.type({
  overview: t.string,
  release_date: t.string, // check out custom codecs to get dates as JS Date objects on decoding
  title: t.string,
})

export const movieListCodec = t.array(movieCodec)

then when you receive the response, you can guard it with the codec

// where you get the response
fetch(someEndpoint)
  .then<unknown>(r => r.json())
  .then(movieCodecList.is)
  .then(verifiedResponse => {
    // verifiedResponse is correctly typed AND it has been actually verified at runtime
  })

I know this answer goes a bit beyond what you asked but keep in mind that runtime checking anything coming from outside your code is recommended!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM