如何在没有大量注释的情况下获得接受 TypeScript 详尽检查的工具?

How can I get tools to accept TypeScript exhaustiveness checking without a lot of comments?

我写了很多使用穷举检查的代码。

在下面的代码中,如果有人添加到 UnitOfTime 并集,带有 _exhaustivenessCheck 的行将(故意)出现类型错误。我喜欢这种编程风格,但是当结合代码覆盖率和强大的 linter 时,它变得很痛苦:

function waterFrequencyToMilliseconds(unitOfTime: UnitOfTime): number {
  switch (unitOfTime) {
    case 'days':
      return number * ONE_DAY;
    case 'weeks':
      return number * ONE_WEEK;
  }
  /* istanbul ignore next */
  // eslint-disable-next-line
  const _exhaustivenessCheck: never = unitOfTime;
}

当我做正确的事情时,我需要告诉 istanbul 和 eslint 让我一个人呆着。

是否有一种标准方法可以处理这种情况,而不必添加“忽略”和“禁用”注释或完全关闭 lint 规则或代码覆盖率?

对于至少回到 TS 3.1.6 的 TypeScript,(我可以轻松测试的最早版本),您不需要像

添加明确的详尽检查
const _exhaustivenessCheck: never = unitOfTime;

用于函数中的最终 switch 语句,如果它们被编译器视为详尽无遗。即这里没有报错:

function waterFrequencyToMilliseconds(number: number, unitOfTime: UnitOfTime): number {
  switch (unitOfTime) {
    case 'days': {
      return number * ONE_DAY;
    }
    case 'weeks': {
      return number * ONE_WEEK;
    }
  }
}

而如果您的 switch 语句不详尽,您将收到错误消息:

function oopsWaterFrequencyToMillis(number: number, unitOfTime: UnitOfTime): number { 
// error! function lacks ending return statement --------------------------> ~~~~~~
  switch (unitOfTime) {
    case 'days': {
      return number * ONE_DAY;
    }
  }
}

因此对于此处列出的特定示例代码,您应该只删除详尽检查。


此外,自 TypeScript 3.7 起,TypeScript 在拉取请求中有 better support for detecting unreachability via control-flow analysis so that you shouldn't need to explicitly throw or return in any situation where the compiler sees that you are in an unreachable part of the code, such as after an exhaustive switch statement. See this comment 实现此功能以获取更多信息。

因此不仅不需要进行明确的详尽检查,这样的检查实际上会在 TS3.7+ 中产生不可达警告:

function explicitExhaustiveCheck(number: number, unitOfTime: UnitOfTime): number {
  switch (unitOfTime) {
    case 'days': {
      return number * ONE_DAY;
    }
    case 'weeks': {
      return number * ONE_WEEK;
    }
  }
  const _exhaustivenessCheck: never = unitOfTime; // error!
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //unreachable code detected.
}

所以你绝对应该取消那个支票。


如果您需要支持旧版本的 TS,并且您的示例代码显示需要进行显式详尽检查,您可能需要用显式 return 语句替换变量声明,例如 return assertNever(unitOfTime) 其中 assertNever() 只接受 never 个参数。这可能会让你的 linters 开心。但就目前而言,没有此类问题的可重现示例,我认为所提出的问题已尽我所能回答。

Playground link to code