Yourin
Yourin

Reputation: 110

TypeScript doesn't infer the type of passed generic

I'm trying to define flexible types for my api responses, but can't figure out how to approach type conversion using TypeScript 4.5.4. I'd like to parse the response and get the type that I'll be using later in the code, the response type is just for proper typing before parse.

TS Playground (EDIT: fixed id)

// this and ReviewResponse are specific to reviews
export type Review = {
  id: number;
  name: string;
  rating: number;
  review: string;
};

export type ReviewResponse = ResponseType<Review>;

// this is a general type placed elsewhere
export type ResponseType<Item> = {
  id: number;
  attributes: {
    [key: string]: Item
  }
}

// parser function to run after fetching the data
function parseResponse(data: ReviewResponse[]): Review[] {
  return data.map((item) => {
    return {
      id: item.id,
      ...item.attributes,
    };
  });
}

Function parseResponse has an error visible below. Why TS doesn't understand that Item is of type Review, what am I missing?:

Type '{ id: number; }[]' is not assignable to type 'Review[]'.
  Type '{ id: number; }' is missing the following properties from type 'Review': name, rating, review (2322)

Upvotes: 1

Views: 68

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250366

If attributes contains an object with the other attributes of the object it's type should be Item, or more specifically Omit<Item, 'id'>.

export type ResponseType<Item> = {
  id: string;
  attributes: Omit<Item, 'id'>
}

// parser function to run after fetching the data
function parseResponse(data: ReviewResponse[]): Review[] {
  return data.map((item) => {
    return {
      id: item.id,
      ...item.attributes,
    };
  });
}

Playground Link

[key: string]: Item means that attributes could have multiple Item properties under different keys. So it could be something like { "A": { /*attributes of Review*/ }, "B": { /*attributes of Review*/ } }

Upvotes: 2

Related Questions