0
votes

I have a function filterAssets which could take 2 different kind of arrays. Below are the 2 different array types:

export interface IResAssetPrice {
  currency: string;
  price: string;
}

export interface IResAssetSupply {
  currency: string;
  availableSupply: string;
}

Some filtering takes place then returns the same array. However I get the following error:

Cannot invoke an expression whose type lacks a call signature. Type '{ (callbackfn: (value: IResAssetPrice, index: number, array: IResAssetPrice[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: IResAssetPrice, index: number, array: IResAssetPrice[]) => any, thisArg?: any): IResAssetPrice[]; } | { ...; }' has no compatible call signatures.ts(2349)

export const filterAssets = (assets: IResAssetPrice[] | IResAssetSupply[]): any => {
  const filtered = assets.filter((asset) => {
    if (asset.availableSupply && asset.availableSupply !== null) {
      return asset;
    }
    if (asset.price && asset.price !== '') {
      return asset;
    }
  });

  return filtered;
};

I assumed it had to do with the expected return type, so I also tried the following to no avail.

export const filterAssets = (assets: IResAssetPrice[] | IResAssetSupply[]): {
  currency: string;
  price: string;
} | {
  currency: string;
  availableSupply: string;
} => {
  const filtered = assets.filter((asset) => {
    if (asset.availableSupply && asset.availableSupply !== null) {
      return asset;
    }
    if (asset.price && asset.price !== '') {
      return asset;
    }
  });

  return filtered;
};
1

1 Answers

0
votes

Ah just found the answer here: Cannot invoke an expression whose type lacks a call signature

TypeScript supports structural typing (also called duck typing), meaning that types are compatible when they share the same members. Your problem is that Apple and Pear don't share all their members, which means that they are not compatible. They are however compatible to another type that has only the isDecayed: boolean member. Because of structural typing, you don' need to inherit Apple and Pear from such an interface.

Was then now able to fix my problem with a 3rd type that was compatible to both current interfaces :)

type AssetResponse = {
  currency: boolean;
  price?: string;
  availableSupply?: string;
};

export const filterAssets = (assets: AssetResponse[]) => {
  const filtered = assets.filter((asset) => {
    if (asset.availableSupply && asset.availableSupply !== null) {
      return asset;
    }
    if (asset.price && asset.price !== '') {
      return asset;
    }
  });