我正在尝试创造一个界面

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

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


当前回答

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

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;

其他回答

只是延伸到上面的酷答案!对于登陆这里的人,同时寻找一个需要能力的部分版本!这里有一个片段,我要采取!

PartialReq

你想要一个接口的部分,但同时需要一些字段!这是如何做到的

export type PartialReq<T, Keys extends keyof T = keyof T> =
    Pick<Partial<T>, Exclude<keyof T, Keys>>
    & {
        [K in Keys]: T[K]
    };

使用的例子

export interface CacheObj<SigType = any, ValType = any> {
    cache: Map<SigType, ValType>,
    insertionCallback: InsertionCallback<SigType, ValType> // I want this to be required
}

// ...

export class OneFlexibleCache<SigType = any, ValType = any> {
    private _cacheObj: CacheObj<SigType, ValType>;

    constructor(
        cacheObj: PartialReq<CacheObj<SigType, ValType>, 'insertionCallback'> // <-- here
                                                                           //  i used it
    ) {
        cacheObj = cacheObj || {};

        this._cacheObj = {

// ...

// _______________ usage
this._caches.set(
    cacheSignature,
    new OneFlexibleCache<InsertionSigType, InsertionValType>({
        insertionCallback // required need to be provided
    })
);

在这里你可以看到它工作得很完美

如未提供要求

更新:对于我在这里暗示的用法,一个更好的答案

我刚从医生那里找到了奥米特。

https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk

我是来加的。但在此之前,我看到了一个很酷的答案。它涵盖了所有:

https://stackoverflow.com/a/48216010/7668448

看看吧!它展示了如何为所有不同版本的Typescript做这件事!为了不重复!去看看!

我用这个:

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

用法:

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

这使得fieldA和fieldB是必需的。

我喜欢将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 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"
}

有一个更简单的解决方案。不需要依赖任何 复杂条件类型(见答案):

是否有方法要求组件或单击进行设置?(包容或)

type MenuItemOr = {
    title: string;
    icon: string;
} & ({ component: object } | { click: boolean }) 
// brackets are important here: "&" has precedence over "|"

let testOr: MenuItemOr;
testOr = { title: "t", icon: "i" } // error, none are set
testOr = { title: "t", icon: "i", component: {} } // ✔
testOr = { title: "t", icon: "i", click: true } // ✔
testOr = { title: "t", icon: "i", click: true, component: {} } // ✔

联合类型(|)对应于包含或。它与非条件属性相交。

使用in操作符将值缩小到其中一个组成部分:

if ("click" in testOr) testOr.click // works 

是否有一种方法要求两个属性都不能设置?(异或或除外)

type MenuItemXor = {
    title: string;
    icon: string;
} & (
        | { component: object; click?: never }
        | { component?: never; click: boolean }
    )

let testXor: MenuItemXor;
testXor = { title: "t", icon: "i" } // error, none are set
testXor = { title: "t", icon: "i", component: {} } // ✔
testXor = { title: "t", icon: "i", click: true } // ✔
testXor = { title: "t", icon: "i", click: true, component: {} } //error,both set

基本上任何一个组件或点击都可以设置,另一个永远不要同时添加。TS可以从MenuItemXor中生成一个有区分的联合类型,它对应于XOR。

对于已接受的答案,MenuItemXor的此异或条件是不可能的。


操场上

从技术上讲,道具?:从来没有决心去支持?:未定义,尽管former常用于说明。