如何为TypeScript多类型商品列表中的选中商品定义类型
多品类商品选中变量的TypeScript类型定义方案
第一步:优化现有类型的可辨识字段
你现有定义中BaseProduct的type字段是宽泛的string类型,无法用于联合类型的自动收窄,首先需要将其修改为泛型约束的字面量类型,让每个子类的type都有唯一固定值:
// 给BaseProduct增加泛型约束,指定type字段的字面量类型 interface BaseProduct<T extends string> { name: string; description: string; price: number; type: T; } interface SomeProduct extends BaseProduct<'someProduct'> { genericAttrOne: string; genericAttrTwo: string; } interface OtherProduct extends BaseProduct<'otherProduct'> { anAttributeOne: string; anAttributeTwo: string; } interface AnotherProduct extends BaseProduct<'anotherProduct'> { anotherAttributeOne: string; anotherAttributeTwo: string; } type Product = SomeProduct | OtherProduct | AnotherProduct; const productsAsArray: Product[] = [];
第二步:定义productSelected的类型
因为选中商品可以是任意品类,且初始状态可能未选中,直接定义为联合类型加空值即可:
let productSelected: Product | null = null; // 用户点击商品时直接赋值即可,类型完全兼容 productSelected = productsAsArray[0];
第三步:类型收窄后访问专属属性
有两种常用的类型收窄方案,可以安全访问不同品类的专属属性:
方案1:利用可辨识联合的type字段收窄(推荐)
if (productSelected) { switch (productSelected.type) { case 'someProduct': // 此分支下TS自动将类型收窄为SomeProduct,可直接访问专属属性 console.log(productSelected.genericAttrOne, productSelected.genericAttrTwo); break; case 'otherProduct': console.log(productSelected.anAttributeOne, productSelected.anAttributeTwo); break; case 'anotherProduct': console.log(productSelected.anotherAttributeOne, productSelected.anotherAttributeTwo); break; } }
方案2:通过in操作符判断专属属性存在收窄
如果不想依赖type字段,也可以直接判断专属属性是否存在来收窄类型:
// 判断genericAttrOne属性存在,自动收窄为SomeProduct类型 if (productSelected && 'genericAttrOne' in productSelected) { console.log(productSelected.genericAttrTwo); } // 判断anAttributeOne属性存在,自动收窄为OtherProduct类型 if (productSelected && 'anAttributeOne' in productSelected) { console.log(productSelected.anAttributeTwo); }
内容的提问来源于stack exchange,提问作者Cristian Flórez
相关产品推荐
相关产品推荐

