通过三元表达式赋值和if-else语句的类型缩小有何不同



根据m是通过三元表达式还是通过if-else语句指定的,类型检查器在print()中键入的m似乎有所不同。print()函数中的第一行和该行下面注释的代码之间有什么区别?

interface Measurement {
unit: string;
}
interface ComputedMeasurement extends Measurement {
compute: (n: number) => number;
}
const measurements = {
'Vitamin D': {
unit: 'mcg',
},
};
const computedMeasurements = {
'Vitamin D (IU)': {
unit: 'IU',
compute: (n: number) => n / 0.025,
},
};
type MeasurementKey = keyof typeof measurements;
type ComputedMeasurementKey = keyof typeof computedMeasurements;
const isMeasurementKey = (k: string): k is MeasurementKey =>
k in measurements;
function print(key: MeasurementKey | ComputedMeasurementKey, amount: number): string {
const m = isMeasurementKey(key) ? measurements[key] : computedMeasurements[key];
// *** Replacing the above line with the below lines eliminates the below error. ***
// let m: Measurement | ComputedMeasurement;
// if (isMeasurementKey(key)) {
//   m = measurements[key];
// } else {
//   m = computedMeasurements[key];
// }
if ('compute' in m) {
// Error: Property 'compute' does not exist on type '{ unit: string; }'.
return `${m.compute(amount)} ${m.unit}`;
}
return `${amount} ${m.unit}`;
}

游乐场链接

有趣的是,let声明后面的if-then-else赋值保留了m的并集类型Measurement | ComputedMeasurement(这是预期行为(,但条件表达式将类型缩小到Measurement,这会触发类型错误。

事实证明,这是条件表达式的预期行为,其中一个选项是另一个选项的子类型,正如本期已关闭的TypeScript问题中所解释的那样。其中一条评论提到,亚型减少有时可能有点不幸,您的例子就是其中之一。

如果使用as constmeasurementscomputedMeasurements声明为只读对象,则可以使用条件表达式而不会出现任何错误,如计算的测量将不再是测量的子类型:

const measurements = {
'Vitamin D': {
unit: 'mcg',
},
} as const;
const computedMeasurements = {
'Vitamin D (IU)': {
unit: 'IU',
compute: (n: number) => n / 0.025,
},
} as const;

但是你也可以使用if-then-else赋值。

TypeScript游乐场

相关内容

  • 没有找到相关文章

最新更新