错误读数为Property 'id' does not exist on type 'never'.

我对TypeScript了解得足够多,以至于我认为Control Flow Analysis会让我在这个场景中被涵盖.当我宣布:

let quantityRange: QuantityLevels | false = false;

并且,在迭代其中一个函数参数时,可以分配QuantityLevels类型的变量may:

priceList.quantityLevels.forEach((ql) => {
  if (ql.min <= quantity && ql.max >= quantity) {
    quantityRange = ql;
  }
});

在这种情况下,我们通过抛出一个错误,消除了函数剩余部分的赋值为quantityRange的可能性.然而,TypeScript推断变量quantityRange只能被赋值为false,对于函数的其余部分,它被键入为never.

当我try 使用quantityRange的属性时,我被拒绝了:

const priceByProduct = priceList.prices[product.id][quantityRange.id].price;
// error: Property 'id' does not exist on type 'never'.

这是怎么回事?如果我分配任务

quantityRange = priceList.quantityLevels[0];

(priceList.quantityLevels被打成Array<QuantityLevels>),那么一切都好了.这让我想到,当谈到TypeScript处理函数/块范围变量的方式时,我必须有一个不完整的理解模型.我通读了打字本手册中的what I think个是relevant sections,结果空手而来(或者可能是空着脑袋).

该代码不会通过build次操作,但在开发和测试环境中,它的工作方式与预期一致.

The code below also rendered in TypeScript playground, along with errors.

function getPrice({ variantID, quantity, priceList }: GetPriceProps) {
  let quantityRange: QuantityLevels | false = false;

  priceList.quantityLevels.forEach((ql) => {
    if (ql.min <= quantity && ql.max >= quantity) {
      quantityRange = ql;
    }
  });

  // quantityRange = priceList.quantityLevels[0];
  // ^ Manually assigning this (which is what's happening in the above for loop) 
  //   makes TS understand.

  if (!quantityRange) {
    throw new Error(`No quantity range found for ${quantity} of ${variantID}.`);
  }

  const product = priceList.targets.find(
    (t) => t.variants.find((v) => v.id === variantID),
  );

  if (!product) {
    throw new Error(`Could not find a product related to variant ${variantID}.`);
  }

  const priceByProduct = priceList.prices[product.id][quantityRange.id].price;
  const priceByVariant = priceList.prices[product.id][quantityRange.id][variantID];

  return (priceByVariant || priceByProduct);
};

type QuantityLevels = {
  id: string;
  min: number;
  max: number;
}

interface NamedEntity {
  id: string;
  name: string; 
};

interface Product extends NamedEntity {
  variants: Array<NamedEntity>;
}

type PriceList = {
  targets: Array<Product>;
  quantityLevels: Array<QuantityLevels>;
  prices: {
    [productID: string]: {
      [quantityLevelID: string]: {
        price: number;
        [variantID: string]: number;
      }
    }
  }
};

type GetPriceProps = {
  variantID: string;
  quantity: number;
  priceList: PriceList;
};

推荐答案

在实例化变量而不是注释时使用type assertion.这将防止TS推断出在该范围的其余部分中只有false个,即使是在代码块中,对于control flow analysis也存在困难.

let quantityRange = false as QuantityLevels | false;

你修改过的TS Playground

Typescript相关问答推荐

TypScript中的算法运算式

无法从应用程序内的库导入组件NX Expo React Native

如何为ViewContainerRef加载的Angular组件实现CanDeactivate保护?

替代语法/逻辑以避免TS变量被分配之前使用." "

TypeScript泛型参数抛出错误—?&#"' 39;预期"

有没有可能使用redux工具包的中间件同时监听状态的变化和操作

如果一个变量不是never类型,我如何创建编译器错误?

当方法参数和返回类型不相互扩展时如何从类型脚本中的子类推断类型

如何在另一个参数类型中获取一个参数字段的类型?

表单嵌套太深

从对象类型描述生成类型

如何将别名添加到vitest配置文件?

在组件卸载时try 使用useEffect清除状态时发生冲突.react +打字

如何在Reaction 18、Reaction-Rout6中的导航栏中获取路由参数

类型脚本中参数为`T`和`t|unfined`的重载函数

推断集合访问器类型

如何在Type脚本中创建一个只接受两个对象之间具有相同值类型的键的接口?

记录的子类型<;字符串,X>;没有索引签名

Select 器数组到映射器的Typescript 泛型

是否有解释为什么默认情况下在泛型类型上访问的属性不是索引访问