【问题标题】:Typescript (Type 'undefined' is not assignable to type) Why is my Array having a | undefined?打字稿(类型“未定义”不可分配给类型)为什么我的数组有一个 |不明确的?
【发布时间】:2019-07-26 07:40:57
【问题描述】:

我有一个名为combinedMarkets 的数组,它是 5 或 3 个不同市场数组的组合。所有这些数组都有以下接口IMarketAsset[]

export interface IMarketAsset {
  exchange: string;
  base: string;
  quote: string;
  price_quote: string;
  timestamp: string;
}

这里是打字稿错误发生的地方:

const combinedMarkets = asset !== 'BTC' && asset !== 'ETH' ?
  btcMarkets.concat(ethMarkets).concat(marketUSD).concat(marketUSDC).concat(marketUSDT) :
  marketUSD.concat(marketUSDC).concat(marketUSDT);

const filteredMarkets = combinedMarkets.length > 0 ? filterByUSDbase(asset, combinedMarkets) : [];

'({ price_quote: string; exchange: string; base: string; quote: string; timestamp: string; } | undefined)[]' 类型的参数不能分配给'IMarketAsset[]' 类型的参数。 输入'{ price_quote: string;交换:字符串;基数:字符串;引用:字符串;时间戳:字符串; } | undefined' 不可分配给类型 'IMarketAsset'。 类型 'undefined' 不可分配给类型 'IMarketAsset'.ts(2345)

const combinedMarkets: ({
  price_quote: string;
  exchange: string;
  base: string;
  quote: string;
  timestamp: string;
} | undefined)[]

为什么combinedMarkets 是IMarketAsset 类型对象或未定义对象的数组?

完整的 combineExchangeData 函数

// Filter by BTC, ETH, USD, USDT or USDC prices
// If asset has BTC/ETH pairing, obtain exchange BTC/ETH price to calculate assets USD/USDT value
export const combineExchangeData =
  (asset: string, { marketBTC, marketETH, marketUSD, marketUSDT, marketUSDC }: IGetMarketsRes) => {
    const btcBasedExchanges = marketBTC.filter((market: IMarketAsset) => market.base === asset);
    const ethBasedExchanges = marketETH.filter((market: IMarketAsset) => market.base === asset);
    const btcUSDTprices = marketUSDT.filter((market: IMarketAsset) => market.base === 'BTC');
    const btcUSDprices = marketUSD.filter((market: IMarketAsset) => market.base === 'BTC');
    const ethUSDTprices = marketUSDT.filter((market: IMarketAsset) => market.base === 'ETH');
    const ethUSDprices = marketUSD.filter((market: IMarketAsset) => market.base === 'ETH');

    const btcPricedMarkets = filterByExchangeBase(btcBasedExchanges, btcUSDTprices, btcUSDprices);
    const ethPricedMarkets = filterByExchangeBase(ethBasedExchanges, ethUSDTprices, ethUSDprices);

    const btcMarkets = btcPricedMarkets.filter((market) => R.not(R.isNil(market)));
    const ethMarkets = ethPricedMarkets.filter((market) => R.not(R.isNil(market)));

    const combinedMarkets = asset !== 'BTC' && asset !== 'ETH' ?
      btcMarkets.concat(ethMarkets).concat(marketUSD).concat(marketUSDC).concat(marketUSDT) :
      marketUSD.concat(marketUSDC).concat(marketUSDT);

    console.log('combinedMarkets', combinedMarkets);
    const filteredMarkets = combinedMarkets.length > 0 ? filterByUSDbase(asset, combinedMarkets) : [];
    console.log('filteredMarkets', filteredMarkets);

    if (R.isEmpty(filteredMarkets)) return [];

    return filteredMarkets.map((market: IMarketAsset) => {
      if (market) {
        return {
          ...market,
          price_quote: formatPrice(market.price_quote)
        }
      }
    });
  };

实用功能

这是我在 main 函数中使用的另外 2 个 util 函数。此外,我已将问题范围缩小到 btcMarketsethMarkets 数组。所以看看filterByExchangeBase

import * as R from 'ramda'

import { USD_CURRENCIES } from '../shared/constants/api'
import { IMarketAsset } from '../shared/types'

const calculateBasePrice = (assetBtcPrice: string | number, btcPrice: string | number) => 
  (Number(assetBtcPrice) * Number(btcPrice)).toString();

export const filterByExchangeBase =
  (exchanges: IMarketAsset[], usdtExchanges: IMarketAsset[], usdExchanges: IMarketAsset[]) =>
    exchanges.map((exchange) => {
      let basePriced = usdtExchanges.filter((btcExchange) => btcExchange.exchange === exchange.exchange)[0];

      if (!basePriced) {
        basePriced = usdExchanges.filter((btcExchange) => btcExchange.exchange === exchange.exchange)[0];
      }

      if (basePriced) {
        const { price_quote: assetBtcPrice } = exchange;
        const { price_quote: btcPrice } = basePriced;

        return {
          ...exchange,
          price_quote: calculateBasePrice(assetBtcPrice, btcPrice)
        }
      }
    });

export const filterByUSDbase = (asset: string, combinedMarkets: IMarketAsset[] | undefined) => {
  if (!combinedMarkets) return [];
  return R.not(R.any(R.equals(asset))(USD_CURRENCIES))
    ? combinedMarkets.filter((marketAsset: IMarketAsset) => {
      if (marketAsset && marketAsset.base) {
        return marketAsset.base === asset;
      }
    }) : [];
}

【问题讨论】:

    标签: javascript arrays typescript


    【解决方案1】:

    问题在于,在我的filterByExchangeBase util 函数中,我使用了.map 而不是.filter,这会导致该数组中有一些undefined 对象。切换到过滤器确保只有现有项目才能进入数组。

    ...

    更新:通过将 .map 更改为 .filter,price_quote 更新不再需要

    重构逻辑以确保如果 btcMarkets 和 ethMarkets 为空,则不会使用它们。

    export const combineExchangeData =
      (asset: string, { marketBTC, marketETH, marketUSD, marketUSDT, marketUSDC }: IGetMarketsRes) => {
        const btcBasedExchanges = marketBTC.filter((market: IMarketAsset) => market.base === asset);
        const ethBasedExchanges = marketETH.filter((market: IMarketAsset) => market.base === asset);
        const btcUSDTprices = marketUSDT.filter((market: IMarketAsset) => market.base === 'BTC');
        const btcUSDprices = marketUSD.filter((market: IMarketAsset) => market.base === 'BTC');
        const ethUSDTprices = marketUSDT.filter((market: IMarketAsset) => market.base === 'ETH');
        const ethUSDprices = marketUSD.filter((market: IMarketAsset) => market.base === 'ETH');
    
        const btcPricedMarkets = notBTCorETH(asset) ? filterCryptoBase(btcBasedExchanges, btcUSDTprices, btcUSDprices) : [];
        const ethPricedMarkets = notBTCorETH(asset) ? filterCryptoBase(ethBasedExchanges, ethUSDTprices, ethUSDprices) : [];
    
        const btcMarkets = R.not(R.isEmpty(btcPricedMarkets)) ? btcPricedMarkets.filter((market: IMarketAsset) => R.not(R.isNil(market))) : [];
        const ethMarkets = R.not(R.isEmpty(ethPricedMarkets)) ? ethPricedMarkets.filter((market: IMarketAsset) => R.not(R.isNil(market))) : [];
    
        const combinedMarkets = notBTCorETH(asset) ?
          btcMarkets.concat(ethMarkets).concat(marketUSD).concat(marketUSDC).concat(marketUSDT) :
          marketUSD.concat(marketUSDC).concat(marketUSDT);
    
        const filteredMarkets = filterByUSDbase(asset, combinedMarkets);
    
        if (R.isEmpty(filteredMarkets)) return [];
    
        return filteredMarkets.map((market: IMarketAsset) => ({
          ...market,
          price_quote: formatPrice(market.price_quote)
        }));
      };
    

    export const filterCryptoBase =
      (exchanges: IMarketAsset[] | any, usdtExchanges: IMarketAsset[], usdExchanges: IMarketAsset[]) => {
        return exchanges.map((exchange: IMarketAsset) => {
          let basePriced = usdtExchanges.filter((btcExchange) => btcExchange.exchange === exchange.exchange)[0];
          if (!basePriced) {
            basePriced = usdExchanges.filter((btcExchange) => btcExchange.exchange === exchange.exchange)[0];
          }
    
          if (exchange && basePriced && exchange.price_quote && basePriced.price_quote) {
            const { price_quote: assetBtcPrice } = exchange; // Asset price in BTC/ETH
            const { price_quote: usdPrice } = basePriced; // BTC/ETH price in USDT/USD
            const price_quote = calculateBasePrice(assetBtcPrice, usdPrice).toString();
    
            return {
              ...exchange,
              price_quote
            }
          }
    
          return null;
        });
      }
    

    【讨论】:

      【解决方案2】:

      尝试将每个选项的类型定义为数组,而不是将它们组合起来:

      const combinedMarkets: {
          price_quote: string;
          exchange: string;
          base: string;
          quote: string;
          timestamp: string;
      }[] | undefined[] = [];
      

      【讨论】:

      • ?但是每个数组都是同一类型 IMarketAsset 所以当我将它们全部连接时,它们仍然是 IMarketAsset 类型
      • 你能发布一个type的例子吗?你说得对,我需要一个同时支持IMarketAsset和数组中未定义的类型。
      【解决方案3】:

      为什么combinedMarkets 要么是数组,要么是IMarketAsset 类型的对象,要么是未定义的对象

      因为任何marketXXX 数组都是IMarketAsset | undefined 的数组(而不仅仅是IMarketAsset

      【讨论】:

      • 是的,我想弄清楚为什么会这样,我想我已经把它缩小到 combinedMarkets 有时在 concat 部分逻辑中包含空数组,所以会尝试过滤出空数组。
      • 好吧,我的修复并不能真正解决问题。我必须使用export const filterCryptoBase = (exchanges: IMarketAsset[] | any 来避免打字稿错误。明天将提供这个作为赏金。
      猜你喜欢
      • 2020-08-27
      • 2021-10-11
      • 2019-07-12
      • 2020-06-29
      • 1970-01-01
      • 1970-01-01
      • 2019-09-25
      • 1970-01-01
      • 2022-08-14
      相关资源
      最近更新 更多