typescript - 打字稿联合类型和推断不同的属性而无需额外的类型检查
问题描述
我在联合类型方面有点挣扎,我想知道打字稿是否可以在没有额外检查的情况下推断出值。假设我有这个接口设置(为简洁起见省略了 IBaseDiscount),其中值可以不同,但嵌套的折扣类型名称是固定的
interface IFlatDiscount extends IBaseDiscount {
value:{ formatted: string; value: number };
discountType: {
name: DiscountType.flat;
id: number;
};
}
interface IOpenDiscount extends IBaseDiscount {
value?: number;
discountType: {
name: DiscountType.open;
id: number;
};
}
export interface IPercentageDiscount extends IBaseDiscount {
value: number;
discountType: {
name: DiscountType.percentage;
id: number;
};
}
export type IDiscount = IOpenDiscount | IPercentageDiscount | IFlatDiscount;
现在在我的代码中,当我尝试使用这些值时,我最终不得不执行以下操作
if (discount.discountType.name === DiscountType.flat && typeof discount.value === 'object) {
// now my value is properly typed -- if I leave out the object check it doesnt know the correct type for the value
}
打字稿是否有适当的方法来根据 discountType.name 推断值,而不是在任何地方对值进行所有检查?
解决方案
首先,您在这里进行了不必要的类型检查:
if (discount.discountType.name === DiscountType.flat &&
typeof discount.value === 'object') {
}
以下就足够了:
if (typeof discount.value === 'object') {
}
如果要根据 确定接口discountType.name
,打字稿无法从嵌套属性类型检查中推断类型。
基本上有两种方式:
- 您使用“as”关键字(因为您确定类型正确):
switch(discount.discountType.name) {
case DiscountType.flat:
console.log((discount as IFlatDiscount).value.formatted);
break;
case DiscountType.open:
console.log((discount as IOpenDiscount).value);
break;
case DiscountType.percentage:
console.log((discount as IPercentageDiscount).value);
}
- 更好的是,您可以使用泛型类型:
export enum DiscountType {
flat,
open,
percentage
}
export interface IGenericDiscount<T extends DiscountType> {
value: T extends DiscountType.flat
? { formatted: string; value: number }
:
(T extends DiscountType.open
? (number | undefined)
: number
);
discountType: {
name: T;
id: number;
}
}
const genericDiscount: IGenericDiscount<DiscountType.open> = JSON.parse('{}');
console.log(genericDiscount.value);
推荐阅读
- unit-testing - 使用 H2 数据库的单元测试存储过程
- c++ - 为什么在 Windows 中运行可执行文件时 Cygwin ssh 服务返回 (rs = 1)
- angular - 如何在更改事件上重新订阅 observable
- laravel - 从存储中获取 MIME 类型的图像?
- python - 使用 readlines() 比创建列表更好吗?
- gem5 - 如何在第 n 条指令处破坏 GDB 中的 gem5 可执行文件?
- python - 不要跳过 pandas.read_excel() 中的空白行
- javascript - 如何构建一个 vue 表单作为组件
- javascript - Webpack DevServer 主机 0.0.0.0 无法在 Windows 上运行
- sip - SIP UA 在重新邀请之前必须等待 Ack 吗?