TypeScript菜单联合类型未报错问题咨询
TypeScript菜单联合类型未报错问题咨询
嘿,我来帮你捋捋这个问题~
先把你的代码清晰列出来,方便理解整个场景:
type MenuItem = { title: string; href: string } type SubMenu = { title: string; submenu: MenuItem[] } const menu: (MenuItem | SubMenu)[] = [ { title: "", href: "" }, { title: "", href: "" }, { title: "", submenu: [ { title: "", href: "" }, { title: "", href: "" }, { title: "", href: "" }, ], }, // 你疑惑的这个对象,TypeScript未报错 { title: "", href: "", submenu: [ { title: "", href: "" }, { title: "", href: "" }, { title: "", href: "" }, ], } ]
为什么这个对象不会触发报错?
这是因为TypeScript的类型系统基于鸭子类型:只要一个对象满足某个类型的所有必要属性,就会被判定为属于该类型,多余的属性不会被视为错误。
你的MenuItem和SubMenu没有设置互斥约束:
MenuItem只要求存在title和href,额外加个submenu属性并不会让它不符合MenuItem的定义;SubMenu只要求存在title和submenu,额外加个href属性也不会让它不符合SubMenu的定义。
所以你添加的这个同时拥有href和submenu的对象,同时符合MenuItem和SubMenu两个类型,自然能被(MenuItem | SubMenu)[]这个联合数组接受,TypeScript也就不会抛出错误。
怎么让这种情况触发错误?
如果你希望MenuItem和SubMenu是互斥的——也就是一个菜单选项要么是普通项(只有href),要么是子菜单(只有submenu),可以给两个类型加上互斥属性约束,用never类型来禁止多余的属性:
// 普通菜单:允许有href,禁止有submenu type MenuItem = { title: string; href: string; submenu?: never } // 子菜单:允许有submenu,禁止有href type SubMenu = { title: string; submenu: MenuItem[]; href?: never } const menu: (MenuItem | SubMenu)[] = [ { title: "", href: "" }, { title: "", href: "" }, { title: "", submenu: [ { title: "", href: "" }, { title: "", href: "" }, { title: "", href: "" }, ], }, // 现在这个对象会触发类型错误 { title: "", href: "", submenu: [ { title: "", href: "" }, { title: "", href: "" }, { title: "", href: "" }, ], } ]
这样修改后,当一个对象同时存在href和submenu时,TypeScript会检测到属性冲突:submenu在MenuItem里被约束为never(不能存在),href在SubMenu里也被约束为never,从而触发类型错误,达到你想要的校验效果。
备注:内容来源于stack exchange,提问作者Tomasz Dańczak
相关产品推荐
相关产品推荐

