Home > Mobile >  Mapped Types with Key Remapping mixed in with other properties
Mapped Types with Key Remapping mixed in with other properties

Time:08-09

I am trying to create a generic type for my API responses. The general form is that I have different formats depending on what API I'm calling, but they follow a general structure.

The main content of the response will be in response.result.content, so I have added that as a generic type. I can use types such as ApiResponseSuccess<MyType> to know that an object with type MyType will be in response.result.content.

However, some APIs will have other properties in response.result that I want to be able to access. I could put something like: [key: string]: any; to get rid of any errors and warnings like below:

//my custom type
  type ApiResponseSuccess<T, O = {}> = {
    message: "Success";
    success: true;
    result: {
      content: T;
      [key: string]: any;
    };
  };

and not have to worry about that, but I would like to type this a bit more strongly. So I am trying to do something like below with key remapping, passing in a second generic type optionally to spread out its properties and add its type to the response type.

// General API Types

//taken directly from the typescript documentation
  type MappedTypeWithNewProperties<O = {}> = {
    [K in keyof O as string]: O[K] //works without errors
  }

//my custom type
  type ApiResponseSuccess<T, O = {}> = {
    message: "Success";
    success: true;
    result: {
      content: T;
      [K in keyof O as string]: O[K]; //causes the following errors
      // Member '[K in keyof' implicitly has an 'any' type 
      // ']' expected.
      // Cannot find name 'O', Cannot find name 'K'
    };
  };

And to use the type,

type AdditionalProps = {
  pageSize: number;
  totalPages: number;
  currentPage: number;
}

const response = ApiResponseSuccess<MyType[], AdditionalProps>;

to dynamically create a type like the following:

type ApiResponseSuccess<MyType[], AdditionalProps> = {
  message: "Success";
  success: true;
  result: {
    content: MyType[];
    pageSize: number;
    totalPages: number;
    currentPage: number;
  }
}

However, trying to follow the documentation, I am not able to write types with key remapping. What is wrong with my code, and what do I need to do to achieve such behaviour?

CodePudding user response:

Try the following snippet. It should work and it's simpler.

type ApiResponseSuccess<T, O = {}> = {
  message: "Success";
  success: true;
  result: {
    content: T;
  } & O;
};

CodePudding user response:

I have figured out what was the problem. The linter errors were not accurate. The issue was the following error:

A mapped type may not declare properties or methods. ts(7061)

So the problem was that I was declaring content: T next to the mapped type, which wasn't allowed.

However, I do need that content: T to represent my type correctly. I have written the following type to avoid this issue:

  type ApiResponseSuccess<T, O extends { content: T } = { content: T }> = {
    message: "Success";
    success: true;
    result: {
      [K in keyof O]: O[K];
    };
  };

Now, the optional type O extends { content: T } and has { content: T } as its default value. With that, the resulting type would contain content: T in K in keyof O.

  • Related