0

I'm trying to render an API response on a React + TypeScript view component. Here are the interfaces that are used to represent the API response (in this case stocks) and API error:

export interface IStocks {
    [key: string]: string;
}

export interface IErrors {
    [key: string]: string;
}

Here is a function that gets the stocks from some API, there are compile time errors which I need help for:

private async getStocks(): Promise<IStocks> {
    /*
      Generic type 'Promise<T>' requires 1 type argument(s).ts(2314)

      Ok, but how do I make this function know about IErrors and IStocks types? What is the correct way?

       */


    try {
        let response = await fetch('http://localhost:8080/api/v1/stocks', {
            method: "get",
            headers: new Headers({
                "Content-Type": "application/json",
                Accept: "application/json"
            })
        });
        return (IStocks) response;

        /*
         'IStocks' only refers to a type, but is being used as a value here.ts(2693)


         I wanted to map the response to 'IStocks' interface simply, my way is incorrect but then how do I do it

         */

    } catch (ex) {
        return (IErrors) ex;
        /*
        'IErrors' only refers to a type, but is being used as a value here.ts(2693)

         I wanted to map the response to 'IErrors' interface simply, my way is incorrect but then how do I do it

        */
    }

    return null;

}

Basically, I want to map the API error object ex to the IErrors interface for type checking and the API response object to the IStocks interface.

What is the correct way to do it?

5
  • Do you mean the function returns a promise of IStocks or IErrors? Maybe look at typescriptlang.org/docs/handbook/advanced-types.html Commented Jun 22, 2019 at 9:51
  • @jonrsharpe Okey, I wanted to make sure that the stocks are in a particular format. Let's forget about errors for now. So how will I do it then? Commented Jun 22, 2019 at 9:54
  • 1
    What do you mean "make sure"? TypeScript doesn't exist at runtime, it can't do any checking, casting or conversion. Commented Jun 22, 2019 at 9:57
  • @jonrsharpe "TS doesn't exist in runtime" so I should use class you mean? I remember reading class getting compiled to js AFAIK Commented Jun 22, 2019 at 9:59
  • 1
    I'd strongly recommend reading up on the basics of the language you're trying to use. You seem to be using Java type casting, which TS doesn't do. The interfaces describe what you're expecting in the response, and as they only use basic JSON types they don't need any conversion. Commented Jun 22, 2019 at 10:06

2 Answers 2

3

For such functionality I would recommend a library like axios.

If for whatever reason you can't use libraries like this, I would make a generic wrapper for the fetch method:

export const typedFetch = <T>(
  request: RequestInfo,
  requestInit?: RequestInit
): Promise<T> => {
  return new Promise(resolve => {
    fetch(request, requestInit)
      .then(response => response.json())
      .then(body => {
        resolve(body);
      });
  });
};

// Usage:
const data = await typedFetch<IStocks[]>(
  "http://localhost:8080/api/v1/stocks",
  {
    method: "get",
    headers: new Headers({
      "Content-Type": "application/json",
      Accept: "application/json"
    })
  }
);

You should probably change how your API handles errors as well, you can't have two separate models for your API response.

You should return all your data in a wrapped response that contains your data as well as other info like potential errors, messages, status codes, etc.

The JSON returned by your API could look like this:

{
    "status": 200,
    "errors": [],
    "data": [
        /* Stocks */
    ]
}

{
    "status": 500,
    "errors": [
        /* ERRORS */
    ],
    "data": []
}

Then you would deserialize your data using a generic model on your client side:

interface IApiResponse<T> {
    status: number;
    errors: IErrors[];
    data: T;
}

const data = await typedFetch<IApiResponse<IStocks[]>>("url", ...);
Sign up to request clarification or add additional context in comments.

Comments

1

Ok, but how do I make this function know about IErrors and IStocks types? What is the correct way?

Promise has a single generic type: the type of the successful response. If you have an error, its type is any, and it's up to you to know what the error actually is.

return (IStocks) response;

That's Java, not TypeScript. In TypeScript, the syntax is

return response as IStocks;

Note however that fetch returns a Promise<Response>. A Response contains more that the body of the response. Read the documentation and/or use your IDE to see what properties and methods exist in Response, and how to properly extract the JSON body from the response.

2 Comments

Response can be in any format and I'm getting this now: Conversion of type 'Response' to type 'IStocks' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Index signature is missing in type 'Response'.ts(2352)
Read the end of my answer. I'm just fixing your syntax error to explain that your type cast syntax is not correct. But there is more: you need to extract the JSON body from the response. The documentation and the IDE are your friends

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.