【问题标题】:Type guard for array element's "possibly undefined" error数组元素的“可能未定义”错误的类型保护
【发布时间】:2021-04-04 18:30:46
【问题描述】:

TSC 给出一个错误,它作为注释添加到代码中。

tsconfig:"noUncheckedIndexedAccess": true

type Tfactors = [number, number, number, number];

export default function changeEnough(pocket: Tfactors, bill: number): boolean {
  const coinToDolarFactors: Tfactors = [0.25, 0.1, 0.5, 0.01];
  let pocketTotal = 0;

  for (let i in pocket) {

    if (pocket[i] !== undefined && coinToDolarFactors[i] !== undefined) {
      //Object is possibly 'undefined'.ts(2532)
      pocketTotal += pocket[i] * coinToDolarFactors[i];
    }
  }

  return pocketTotal >= bill;
}

我这样解决了这个问题:

type Tfactors = [number, number, number, number];

export default function changeEnough(pocket: Tfactors, bill: number): boolean {
  const coinToDolarFactors: Tfactors = [0.25, 0.1, 0.5, 0.01];
  let pocketTotal = 0;

  for (let i in pocket) {
    const pocketValue = pocket[i];
    const factor = coinToDolarFactors[i];
    if (pocketValue !== undefined && factor !== undefined) {
      pocketTotal += pocketValue * factor;
    }
  }

  return pocketTotal >= bill;
}

我是 TypeScript 的新手,我不知道这是解决此问题的最佳方法。我可以在不声明pocketValuefactor 变量以及不使用! 使TSC 静音的情况下解决这个问题吗?

【问题讨论】:

  • 我在打字稿操场上看不到问题。
  • "noUncheckedIndexedAccess": true
  • typescript 没有深入到类型保护 pocket[i]coinToDolarFactors[i],因此在 if block 内,它丢失了该类型保护的上下文。也就是说,您使用 const 的方法效果很好,因为 TS 肯定知道它在 const 分配中是未定义的;或者,你可以for (let _i in pocket) { const i = _i as '0'|'1'|'2'|'3'; ...},因为Tfactors 是一个元组类型。
  • @ABOS as '0'|'1'|'2'|'3' 是一种硬编码。但我已经定义了一个元组。为什么元组不保证索引在范围内?

标签: arrays typescript undefined typeguards


【解决方案1】:

如果您不想使用! 使 TSC 静音或将数组元素分配给新变量,则可以显式键入数组索引,即

type Tfactors = [number, number, number, number];

export default function changeEnough(pocket: Tfactors, bill: number): boolean {
  const coinToDolarFactors: Tfactors = [0.25, 0.1, 0.5, 0.01];
  let pocketTotal = 0;

  for (let _i in pocket) {
    /* --  type it explicitly here -- */
    let i = _i as Exclude<keyof Tfactors, keyof []>;
    // *if* check is not required if you are confident they are defined at runtime  
    if (pocket[i] !== undefined && coinToDolarFactors[i] !== undefined) {
      //Object is possibly 'undefined'.ts(2532)
      pocketTotal += pocket[i] * coinToDolarFactors[i];
    }
  }

  return pocketTotal >= bill;
}

【讨论】:

  • 它仍然很奇怪,有点像手动触摸!运营商,但这个答案适合这个问题。谢谢。
  • 我觉得它非常难看;)-对我来说,它与使用打字稿的目标相矛盾-例如项目可维护性。在我看来,noUncheckedIndexedAccess 默认应该是false
  • @TomaszGawel, noUncheckedIndexedAccess 在大多数情况下仍然非常有用,不应仅仅因为它不涵盖某些corner 情况而将其禁用。也许未来版本的打字稿会改进这种情况下的类型检查:)
【解决方案2】:

从文档Pedantic Index Signature Checks (--noUncheckedIndexedAccess),我们知道

使用--noUncheckedIndexedAccess 的一个结果是,对数组的索引也会受到更严格的检查,即使在边界检查循环中也是如此。

在这种新模式下,每个属性访问(如foo.bar)或索引访问(如foo["bar"])都被视为潜在undefined

解决方案:

如果您需要访问该属性,您要么必须先检查其是否存在,要么使用非空断言运算符(后缀 ! 字符)。

// Checking if it's really there first.
const pocketValue = pocket[i];
const factor = coinToDolarFactors[i];
if (pocketValue !== undefined && factor !== undefined) {
  pocketTotal += pocketValue * factor;
}


// Basically saying "trust me I know what I'm doing"
// with the '!' non-null assertion operator.
pocketTotal += pocket[i]! * coinToDolarFactors[i]!;

【讨论】:

  • 感谢您提供信息。但是您的第一个解决方案已经在问题中,而另一个已被问题排除。
【解决方案3】:

我可以在不声明 pocketValue 和 factor 变量的情况下解决这个问题吗[或]不使用!将 TSC 静音。

不,很遗憾,你不能。

【讨论】:

    猜你喜欢
    • 2021-10-31
    • 2017-11-11
    • 2022-06-28
    • 2023-03-06
    • 2021-06-05
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    • 2020-11-11
    相关资源
    最近更新 更多