如何在Vue中解决TS类型错误:MenuOptionWithEx不是MenuOption的子类型?

作者站长头像
站长
· 阅读数 13

TS 的 vue 项目中,有如下代码块简化如下:

<n-menu
  :render-extra="renderMenuExtra"
/>

其中,render-extra 报错为:如何在Vue中解决TS类型错误:MenuOptionWithEx不是MenuOption的子类型?

项目地址: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个回答
avatar
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,不过不建议这样子做

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