Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/grails/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
typescript接口需要存在两个属性之一_Typescript - Fatal编程技术网

typescript接口需要存在两个属性之一

typescript接口需要存在两个属性之一,typescript,Typescript,我正在尝试创建一个可以 export interface MenuItem { title: string; component?: any; click?: any; icon: string; } 是否有方法要求设置组件或单击 有没有办法要求两个属性都不能设置 我最后做了: export interface MenuItem { title: string; icon: string; } export interface MenuItemComponent ex

我正在尝试创建一个可以

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>;
    
    appMenuItems:数组;
    

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

    不能使用单个接口,因为类型没有条件逻辑,也不能相互依赖,但可以通过拆分接口:

    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;
    

    没有多个接口的替代方案是

    export type MenuItem = {
      title: string;
      component: any;
      icon: string;
    } | {
      title: string;
      click: any;
      icon: string;
    };
    
    const item: MenuItem[] = [
      { title: "", icon: "", component: {} },
      { title: "", icon: "", click: "" },
      // Shouldn't this error out because it's passing a property that is not defined
      { title: "", icon: "", click: "", component: {} },
      // Does error out :)
      { title: "", icon: "" }
    ];
    
    我在上个月也问过类似的问题

    上述内容可以简化,但可能更容易阅读,也可能不容易阅读

    export type MenuItem = {
      title: string;
      icon: string;
    } & (
     {component: any} | {click: string}
    )
    

    请注意,所有这些都不会阻止您同时添加这两个属性,因为TypeScript允许在使用和/或查看的对象上使用额外属性。借助TypeScript 2.8中添加的
    排除
    类型,提供了一种需要至少一组属性的通用方法:

    type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
        Pick<T, Exclude<keyof T, Keys>> 
        & {
            [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>
        }[Keys]
    
    type RequireOnlyOne<T, Keys extends keyof T = keyof T> =
        Pick<T, Exclude<keyof T, Keys>>
        & {
            [K in Keys]-?:
                Required<Pick<T, K>>
                & Partial<Record<Exclude<Keys, K>, undefined>>
        }[Keys]
    
  • Pick
    from
    requireateLeastone
    变成
    {title:string,icon:string}
    ,这是未包含在
    'click'|'component'中的键的不变属性。

  • {[K in Keys]-?:必需和部分}[Keys]
    来自
    requirealeastone
    成为

    { 
        component: Required<{ component?: number }> & { click?: number }, 
        click: Required<{ click?: number }> & { component?: number } 
    }[Keys]
    
    最终变成

    {component: number, click?: number} | {click: number, component?: number}
    
  • 上述步骤1和步骤2的交点

    { title: string, icon: string} 
    & 
    ({component: number, click?: number} | {click: number, component?: number})
    
    简化为

    { title: string, icon: string, component: number, click?: number} 
    | { title: string, icon: string, click: number, component?: number}
    

  • 我喜欢使用
    Pick
    以及包含所有属性的基本类型来建立这些条件需求

    interface MenuItemProps {
      title: string;
      component: any;
      click: any;
      icon: string;
    }
    
    export interface MenuItem =
      Pick<MenuItemProps, "title" | "icon" | "component"> |
      Pick<MenuItemProps, "title" | "icon" | "click">
    
    接口菜单扩展{
    标题:字符串;
    组成部分:任何;
    点击:任意;
    图标:字符串;
    }
    导出接口菜单项=
    挑|
    挑
    

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

    仅扩展上述酷答案!对于那些在这里登陆的人来说,他们正在搜索一个具有所需功能的部分版本!这里是我制作的一个片段

    部分需求 您希望有一个部分的接口,但同时需要一些字段!这是怎么做的

    导出类型PartialReq=
    挑
    & {
    [K in键]:T[K]
    };
    
    举例
    导出接口CacheObj{
    缓存:映射,
    insertionCallback:insertionCallback//我希望这是必需的
    }
    // ...
    导出类OneFlexibleCache{
    private_cacheObj:cacheObj;
    建造师(
    cacheObj:PartialReq/不需要使用。我们可以简化它:

  • 是否有方法要求设置组件或单击?(包括
  • |
    )对应于inclusive
    。它具有非条件属性

  • 有没有办法要求两个属性都不能设置?(独占
    /
    异或
  • 基本上,可以设置
    组件
    单击
    ,同时添加另一个组件。TS可以利用
    菜单项异或
    ,对应于
    异或

    注意:
    MenuItemXor
    的此
    XOR
    条件不适用于


    我用这个:

    类型RequireField=T&Required
    
    用法:

    让a:RequireField;
    
    这就需要
    fieldA
    fieldB

    另一种解决方案:

    type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
    
    
    type RequiredKeys=必需&省略;
    
    类型MenuItem2=所需键;
    
    很有意思。我以前从未导出过“类型”。所以它只是意味着MenuItem可以是一个或另一个?我比下面的更喜欢它。帮助我理解“类型”的链接嗨,伙计们,你们如何强制在其中一个界面之间进行选择,但不能同时选择两者?对于这种类型,同时具有
    组件
    单击
    的对象不会出错…@DanielRamos您可以添加
    单击?:在
    组件菜单项下从不
    组件?:在
    单击菜单项下从不
    任何方法是否与参数解构兼容?如果我尝试
    函数myFunc({title,icon,component,click}:MenuItem),会出现TS错误
    属性“component”在类型“MenuItem”上不存在。属性“click”在类型“MenuItem”上不存在。非常感谢您提供的描述性示例。非常有用。非常感谢您提供的信息丰富且格式良好的响应。我一直在玩这个示例,以便更好地理解它。如果您提供
    componT
    单击
    any
    之外的类型,至少具有一组有效属性的对象将通过。我假设这是因为该类型减少为
    {title:string,icon:string,component:any}{title:string,icon:string,click:any}
    其中说明类型是3个属性,而不是4个属性,其中一个属性是可选的。我正在尝试查找有关在映射表示法中使用数组的文档,但无法找到。有人能解释表达式
    [K in keys]中的连字符(减号)是什么吗-
    是否?@Lopsped它删除了原始对象
    T
    中可能存在的
    K
    的任何可选修饰符。有关其用途,请参见
    [K in key]-?:
    特别是:我刚刚做了一些测试,看起来它实际上对最终结果没有影响,但我把它放进去只是为了确定
    requireateastone
    的行为方式是相同的,而不管
    键指定的属性最初是否可选。注意:这是OFI的一部分在Microsoft Azure Typescript SDK中,您可以使用
    提取
    标题
    图标
    
    interface MenuItemProps {
      title: string;
      component: any;
      click: any;
      icon: string;
    }
    
    export interface MenuItem =
      Pick<MenuItemProps, "title" | "icon" | "component"> |
      Pick<MenuItemProps, "title" | "icon" | "click">
    
    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: {} } // ✔
    
    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 are set
    
    type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
    
    
    type MenuItem2 = RequiredKeys<MenuItem, "component" | "click">;