TypeScript:RegExp的元素隐式具有“ any”类型

时间:2020-06-02 19:24:36

标签: javascript arrays typescript object implicit-conversion

因此,我想创建一个函数,该函数将使用一个持续时间字符串(例如12ms7.5 MIN400H),将其解析并将其转换为毫秒。

const units = {
  MS: 1,
  S: 1 * 1000,
  MIN: 60 * 1 * 1000,
  H: 60 * 60 * 1 * 1000
}

export function toMS(str: string): number {
  let regex = /^(?<number>\d+(?:\.\d+)?)(?:\s*(?<unit>MS|S|MIN|H))?$/i

  if (!regex.test(str)) {
    throw new TypeError(`Expected a duration, got: ${str}`)
  }

  let match = str.match(regex)

  let number = Number(match?.groups?.number)
  let unit = (match?.groups?.unit || 'ms').toUpperCase()

  return Math.floor(number * units[unit])
}

因此,函数toMS()接受一个字符串,测试所提供的字符串是否有效(number + whitespace (optional) + unit abbr (optional)),以及它是否有效-使用{ {1}}。

一切正常,直到:str.match(regex)。它给我一个错误:units[unit]

在使用函数参数和类构造函数之前,我遇到过相同的错误,并且由于用户提供了数据,因此很容易解决。但是现在我不知道如何解决这个问题,因为我不能强迫Element implicitly has an 'any' type because expression of type 'string' can't be used to index type具有str.match(regex).groups.unit这样的特定类型。

我知道也可以使用: 'MS | S | MIN | H创建 tsconfig.json ,但就我而言,这根本不好。

1 个答案:

答案 0 :(得分:1)

问题在于TypeScript无法知道您的正则表达式是否真正匹配MS|S|MIN|H。这是dependent types的领土,而TypeScript还没有那么强大。

TypeScript唯一了解的是您匹配的内容将是string,因为match?.groups?.unit'ms'表达式都产生string

您可以做的是让TypeScript知道您的units是一个对象,其键类型为string,值类型为number,并检查您是否匹配的对象是units对象上的属性。像这样:

const units: { [k: string]: number } = { // letting TypeScript know
  MS: 1,
  S: 1 * 1000,
  MIN: 60 * 1 * 1000,
  H: 60 * 60 * 1 * 1000,
};

export function toMS(str: string): number {
  const regex = /^(?<number>\d+(?:\.\d+)?)(?:\s*(?<unit>MS|S|MIN|H))?$/i;

  if (!regex.test(str)) {
    throw new TypeError(`Expected a duration, got: ${str}`);
  }

  const match = str.match(regex);
  const number = Number(match?.groups?.number);
  const unit = (match?.groups?.unit || 'ms').toUpperCase();

  if (unit in units) { // checking whether your matched string is something you can handle, in runtime
    return Math.floor(number * units[unit]);
  } else {
    throw new Error(`couldn't find units! :(`);
  }
}