如何在Vue中解决TS类型错误:MenuOptionWithEx不是MenuOption的子类型?
TS 的 vue 项目中,有如下代码块简化如下:
<n-menu
:render-extra="renderMenuExtra"
/>
其中,render-extra
报错为:
项目地址:https://github.com/lingkai5wu/link-admin问题代码位于这里类型位于这里
MenuOptionWithEx
是我扩展 MenuOption
的类型,相关信息如下:
type MenuOptionWithEx = MenuVO &
MenuOption & {
meta?: RouteMeta
}
export interface MenuVO {
id: number
pid: number
type: MenuTypeEnum
label: string | null
path: string | null
}
// MenuOption 为 Naive UI 内置类型
export type MenuOption = (MenuOptionSharedPart & {
/** @deprecated */
title?: string | (() => VNodeChild);
}) | (MenuOptionSharedPart & {
label?: string | (() => VNodeChild);
});
// 同上
export interface MenuOptionSharedPart {
key?: Key;
disabled?: boolean;
icon?: () => VNodeChild;
children?: Array<MenuOption | MenuGroupOption | MenuDividerOption>;
extra?: string | (() => VNodeChild);
props?: HTMLAttributes;
show?: boolean;
[key: string]: unknown;
/** @deprecated */
titleExtra?: string | (() => VNodeChild);
}
// RouteMeta 为 Vue Router 内置类型
export declare interface RouteMeta extends Record<string | number | symbol, unknown> {
}
我尝试使用联合类型扩展 MenuOptionWithEx
,使 MenuOptionWithEx
为子类型,MenuOption
为父类型,期望满足 TS 的要求,但仍然报错,如上。经过测试,我发现将 MenuOptionWithEx
中的 MenuVO
从联合类型中移除,就不会出现报错,但这不符合业务逻辑...
我也尝试直接继承 MenuOption
,但 MenuOption
是联合类型,似乎没法直接继承。
回复
1个回答

test
2024-06-20
这涉及到一个 协变逆变 概念
对于函数参数是反过来,是父类型赋要值给子类型,符合类型安全,可以做个简单的例子:
interface Animal {}
interface Dog extends Animal {
jiao: () => void
}
interface Cat extends Animal {
miao: () => void
}
function foo(bar: (arg: Animal) => void) {
// bar 的参数是 Animal ,猫也是 animal 因此传个猫是可以的
let cat: Cat = { miao: () => {}}
bar(cat)
}
// 假设 (a: Dob) => void 能赋值给 (a: Animal) => void
foo((a: Dog) => {
// 则这里类型不安全,因为这里实际是传入 cat类型,没有 jiao 这个方法
a.jiao()
})
当然你可以把这个开关关掉 strictFunctionTypes
,不过不建议这样子做
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容