错误读数为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;
};