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
fromrequireateLeastone
变成{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">;