我正在尝试创造一个界面

export interface MenuItem {
  title: string;
  component?: any;
  click?: any;
  icon: string;
}

是否有方法要求组件或单击进行设置 是否有一种方法要求两个属性都不能设置?


当前回答

最后我这样做了:

export interface MenuItem {
  title: string;
  icon: string;
}

export interface MenuItemComponent extends MenuItem{
  component: any;
}

export interface MenuItemClick extends MenuItem{
  click: any;
}

然后我用了:

 appMenuItems: Array<MenuItemComponent|MenuItemClick>;

但希望有一种方法可以用单一界面来建模。

其他回答

这里有一个简单的方法来实现其中一个,但不是两个

type MenuItem =  {
  title: string;
  component: any;
  click?: never;
  icon: string;
} | {
  title: string;
  component?: never;
  click: any;
  icon: string;
}

// good
const menuItemWithComponent: MenuItem = {
  title: 'title',
  component: "my component",
  icon: "icon"
}

// good
const menuItemWithClick: MenuItem = {
  title: 'title',
  click: "my click",
  icon: "icon"
}

// compile error
const menuItemWithBoth: MenuItem = {
  title: 'title',
  click: "my click",
  component: "my click",
  icon: "icon"
}

不是用一个接口,因为类型没有条件逻辑,不能相互依赖,但你可以通过分离接口:

export interface BaseMenuItem {
  title: string;
  icon: string;
}

export interface ComponentMenuItem extends BaseMenuItem {
  component: any;
}

export interface ClickMenuItem extends BaseMenuItem {
    click: any;
}

export type MenuItem = ComponentMenuItem | ClickMenuItem;

还有另一个解决方案:

type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;

type MenuItem2 = RequiredKeys<MenuItem, "component" | "click">;

我喜欢将Pick与包含所有属性的基本类型一起使用,以建立这些类型的条件需求。

interface MenuItemProps {
  title: string;
  component: any;
  click: any;
  icon: string;
}

export interface MenuItem =
  Pick<MenuItemProps, "title" | "icon" | "component"> |
  Pick<MenuItemProps, "title" | "icon" | "click">

这样既干净又灵活。您可以任意地复杂化您的需求,断言诸如“需要所有属性,只需要这两个属性,或者只需要这一个属性”之类的东西,同时保持您的声明简单易读。

我用这个:

type RequireField<T, K extends keyof T> = T & Required<Pick<T, K>>

用法:

let a : RequireField<TypeA, "fieldA" | "fieldB">;

这使得fieldA和fieldB是必需的。