首页 > 解决方案 > 类型 'null' 必须有一个 '[Symbol.iterator]()' 方法

问题描述

我在下面有一个函数,它接受数值并将其解析为货币值,如 11k、1m 等......它完成了任务,但我在这一行收到 ts 错误:

const [match] = `${value / divider}`.match(regx);

错误

类型“null”必须具有返回 iterator.ts(2488) 的“Symbol.iterator”方法

完整代码

export function getCurrencyValue(value: number) {
  const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
  const regx = new RegExp('^-?\\d+(?:.\\d{0,1})?');
  let formatedValue = '';

  ranges.forEach(range => {
    const { divider, suffix } = range;

    if (value >= divider) {
      const [match] = `${value / divider}`.match(regx);

      if (match) {
        formatedValue = `${match}${suffix}`;
      }
    }
  });

  return formatedValue || value;
}

标签: typescript

解决方案


你不能解构null,所以

const [match] = `${value / divider}`.match(regx);

...如果没有匹配会抛出,因为在没有匹配时match返回null。您需要将其拆分为两个语句,或使用|| []技巧或类似方法。查看您的完整代码,在这里解构似乎没有帮助(因为可能null),简单地说:

const match = `${value / divider}`.match(regx);

if (match) {
  formatedValue = `${match[0]}${suffix}`;
}

错误消息说明它所说的原因是您正在执行的解构类型(使用[])依赖于从您正在解构的事物(的结果)中获取迭代器match。您可以使用它的方法从某事物中获取迭代器Symbol.iterator

const it = `${value / divider}`.match(regx)[Symbol.iterator]();

由于match可以返回的东西之一是null,并且null没有(也不能)有Symbol.iterator属性,TypeScript 抱怨它。


旁注:forEach这里似乎不是正确的工具,因为您想在第一次匹配时停止。现在,您将写入formattedValue范围1e6,然后用格式化1e3范围的结果覆盖它。

for-of将是一个不错的选择:

export function getCurrencyValue(value: number) {
  const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
  const regx = new RegExp('^-?\\d+(?:.\\d{0,1})?');

  for (const { divider, suffix } of ranges) {
    if (value >= divider) {
      const match = `${value / divider}`.match(regx);
      if (match) {
        return `${match[0]}${suffix}`;
      }
    }
  });

  return String(value); // Presumably you always want it to be a string
}

为了清楚起见,我也可能使用文字正则表达式语法(不必双转义反斜杠),并将函数ranges和函数都移到regx函数之外,这样它们就不会每次都重新创建(因为这是在一个模块中,并且单独因为正则表达式没有gory标志):

const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = /^-?\d+(?:.\d{0,1})?/;
export function getCurrencyValue(value: number) {

  for (const { divider, suffix } of ranges) {
    if (value >= divider) {
      const match = `${value / divider}`.match(regx);
      if (match) {
        return `${match[0]}${suffix}`;
      }
    }
  });

  return String(value); // Presumably you always want it to be a string
}

你说过你不允许for-of在你的环境中使用,因为你正在编译到 ES5 并且不允许依赖 regenerator-runtime。因此forEach,您需要的是some

const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = /^-?\d+(?:.\d{0,1})?/;
export function getCurrencyValue(value: number) {
  let formattedValue = String(value); // Presumably you want it to always be a string

  // Not allowed to use for-of, and the rule saying not to use it also doesn't like `for` loops, so...
  ranges.some(({ divider, suffix }) => {
    if (value >= divider) {
      const match = `${value / divider}`.match(regx);
      if (match) {
        formattedValue = `${match[0]}${suffix}`;
        return true;
      }
    }
    return false;
  });

  return formattedValue;
}

或与reduce

const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = /^-?\d+(?:.\d{0,1})?/;
export function getCurrencyValue(value: number) {

  // Not allowed to use for-of, and the rule saying not to use it also doesn't like `for` loops, so...
  return ranges.reduce((formattedValue, { divider, suffix }) => {
    if (value >= divider) {
      const match = `${value / divider}`.match(regx);
      if (match) {
        formattedValue = `${match[0]}${suffix}`;
      }
    }
    return formattedValue;
  }, String(value)); // Presumably you always want it to be a string
}

推荐阅读