如何根据数组元素component属性值正确标注动态数组TypeScript类型
实现方案
这类需求完全没有超出TypeScript的能力边界,通过判别联合(Discriminated Unions,也叫可辨识联合)类型即可精准实现属性的自动校验。
核心实现逻辑
- 把不同
component值对应的结构拆成独立的类型分支,每个分支里把component标注为对应的字符串字面量类型,同时声明该分支下必填的附加属性 - 新增一个兜底分支,匹配所有未明确定义规则的
component值,不强制要求附加属性 - 把所有分支类型联合起来,作为数组元素的统一类型,TypeScript就会根据
component的取值自动收窄类型,校验对应必填属性是否存在
完整类型代码示例
// 定义mockup组件对应的项类型:component为"mockup"时必须传src type MockupItem = { id: number; component: "mockup"; src: string; } // 定义header组件对应的项类型:component为"header"时必须传title、subtitle type HeaderItem = { id: number; component: "header"; title: string; subtitle: string; } // 兜底类型:匹配其他任意component值,无强制附加属性要求 type OtherComponentItem = { id: number; component: string; // 允许传入任意自定义属性,不做强制校验 [key: string]: any; } // 联合所有分支,得到数组元素的统一类型 type ComponentArrayItem = MockupItem | HeaderItem | OtherComponentItem;
校验效果
给数组标注ComponentArrayItem[]类型后,TypeScript会自动做校验:
const componentList: ComponentArrayItem[] = [ { id: 1, component: "mockup", src: "some-link" }, // 校验通过 { id: 2, component: "header", title: "Some Title", subtitle: "Lorem ipsum..." }, // 校验通过 { id: 3, component: "footer", copyright: "xxx" }, // 校验通过,无强制附加属性要求 // { id: 4, component: "mockup" } // 类型报错:缺少必填属性src // { id: 5, component: "header", title: "xxx" } // 类型报错:缺少必填属性subtitle ]
额外便利:渲染时自动类型收窄
遍历数组做组件渲染时,只要判断了当前项的component值,TypeScript会自动推导当前项的可用属性,不需要手动做类型断言:
componentList.forEach(item => { switch(item.component) { case "mockup": // 此处TS自动识别item为MockupItem类型,可直接访问src属性 renderMockup(item.src) break case "header": // 此处TS自动识别item为HeaderItem类型,可直接访问title、subtitle属性 renderHeader(item.title, item.subtitle) break default: // 此处TS自动识别item为OtherComponentItem类型,无强制属性要求 renderOther(item) } })
如果你的业务场景只允许使用预先定义好的几个组件,不允许传入其他component值,直接去掉
OtherComponentItem这个兜底分支即可,此时传入未定义的component值时TS也会直接抛错。
内容的提问来源于stack exchange,提问作者Rubek Joshi
相关产品推荐
相关产品推荐

