2

So running into another vague Typescript error.

I have the following function fetchAllAssets which ends with dispatching an action and running the responses through a function called formatAssets.

And the error is on the responses array.

export const fetchAllAssets = () => (dispatch: DispatchAllAssets) => {
  dispatch(actionGetAllAssets());
  return fetchAll([getPrices(), getAvailableSupply()]).then((responses) =>
    dispatch(actionSetAllAssets(formatAssets(responses))));
}

The formatAssets function:

export const formatAssets = (responses: IResponseConfig[]) => {
  let prices: any;
  let availableSupplies: any;
  console.log('responses', responses);
  responses.forEach((response: IResponseConfig) => {
    const { config } = response;
    const { url } = config;
    if (url.includes('prices')) {
      prices = response.data;
    } else if (url.includes('dashboard')) {
      availableSupplies = cleanAssets(response.data);
    }
    return {
      prices,
      availableSupplies
    };
  });

The Error

enter image description here

Argument of type '[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]' is not assignable to parameter of type 'IResponseConfig[]'. Type '{}' is missing the following properties from type 'IResponseConfig': config, data ts(2345)

Here is what the interface for IResponseConfig looks like:

export interface IResponseConfig {
  config: {
    adapter: any;
    baseUrl: string;
    headers: {};
    maxContentLength: number;
    method: string;
    params: {
      key: string;
    }
    timeout: number;
    transformRequest: {};
    transformResponse: {};
    url: string;
    validateStatus: any;
    xsrfCookieName: string;
    xsrfHeaderName: string;
  };
  data: IAssetResponse[];
  headers?: {};
  request?: XMLHttpRequest;
  upload?: XMLHttpRequestUpload;
  status?: number;
  statusText?: string;
}

And here is what responses is:

enter image description here

What shape should IResponseConfig take in order for the error to go away?

Signature of fetchAll

// @TODO Fix any type.
export const fetchAll = (array: any) => Promise.all(array);

Also I was able to remove the error by making all keys optional (hack?)

export interface IResponseConfig {
  config?: any;
  data?: IAssetResponse[];
  headers?: any;
  request?: XMLHttpRequest;
  upload?: XMLHttpRequestUpload;
  status?: number;
  statusText?: string;
}

What IAssetResponse looks like (the actual data I care about)

export interface IAssetResponse {
  [key: string]: string | undefined;
  currency: string;
  price?: string;
  availableSupply?: string;
  maxSupply?: string;
}
Leon Gaban
  • 36,509
  • 115
  • 332
  • 529
  • It seems like it's actually an issue with `fetchAll`. What's its signature? – p.s.w.g Mar 06 '19 at 20:33
  • @p.s.w.g added it! Also found out if I added `?` to all the keys the error goes away, but I feel that is a hack? – Leon Gaban Mar 06 '19 at 20:41
  • You probably don't want all parameters to be optional, that is most likely a non-deal hack/workaround for the actual issue here. I agree, something is probably not right with `fetchAll`. You have something returning an array of untyped objects, so that's all it can guess at here. You need to add typedefs everywhere you can to avoid issues like these. – Chris Barr Mar 06 '19 at 20:49

1 Answers1

1

It looks like you need to define fetchAll as a generic function, like this:

export const fetchAll = <T extends {}>(array: (T | Promise<T>)[]) => Promise.all(array);

NOTE: See this question for a discussion on why <T>(array T[]) => ... fails to parse as you might expect.

Assuming, that getPrices and getAvailableSupply both return either a IResponseConfig or Promise<IResponseConfig>, the parameter responses will be inferred to be of type IResponseConfig[].

If this is not the case, you may have to add some additional conversions, type hints, or assertions to coerce them into a consistent interface.

p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • Hmm thanks, trying to wrap my head about the `` currently getting `Argument of type 'Promise[]' is not assignable to parameter of type 'IResponseConfig[]'. Type 'Promise' has no properties in common with type 'IResponseConfig'` wondering if for the sake of another dev understanding context, `any` would suffice, since the arrays are strongly typed elsewhere. – Leon Gaban Mar 06 '19 at 21:06
  • @LeonGaban Ahh, I should have accounted for `Promise` in the parameter type hint. See my updated answer. Hopefully this helps. – p.s.w.g Mar 06 '19 at 21:58
  • Sweet Yes that worked! :D I don't need to rely on `any` anymore. And great link which linked to generics: https://basarat.gitbooks.io/typescript/content/docs/types/generics.html – Leon Gaban Mar 07 '19 at 05:19