我正在尝试创造一个界面
export interface MenuItem {
title: string;
component?: any;
click?: any;
icon: string;
}
是否有方法要求组件或单击进行设置 是否有一种方法要求两个属性都不能设置?
我正在尝试创造一个界面
export interface MenuItem {
title: string;
component?: any;
click?: any;
icon: string;
}
是否有方法要求组件或单击进行设置 是否有一种方法要求两个属性都不能设置?
当前回答
这里有一个简单的方法来实现其中一个,但不是两个
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"
}
其他回答
在TypeScript 2.8中添加的Exclude类型的帮助下,提供了一种要求至少一组属性中的一个的通用方法:
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]
下面是一个TypeScript游乐场链接,展示了两者的作用。
RequireOnlyOne的警告是TypeScript在编译时并不总是知道运行时存在的每个属性。因此,显然RequireOnlyOne不能做任何事情来防止它不知道的额外属性。我提供了一个示例,说明RequireOnlyOne如何错过playground链接末尾的内容。
使用以下示例快速概述它的工作原理:
interface MenuItem {
title: string;
component?: number;
click?: number;
icon: string;
}
type ClickOrComponent = RequireAtLeastOne<MenuItem, 'click' | 'component'>
Pick<T, Exclude<keyof T, Keys>> from RequireAtLeastOne becomes { title: string, icon: string}, which are the unchanged properties of the keys not included in 'click' | 'component' { [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>> }[Keys] from RequireAtLeastOne becomes { component: Required<{ component?: number }> & { click?: number }, click: Required<{ click?: number }> & { component?: number } }[Keys] Which becomes { component: { component: number, click?: number }, click: { click: number, component?: number } }['component' | 'click'] Which finally becomes {component: number, click?: number} | {click: number, component?: number} The intersection of steps 1 and 2 above { title: string, icon: string} & ({component: number, click?: number} | {click: number, component?: number}) simplifies to { title: string, icon: string, component: number, click?: number} | { title: string, icon: string, click: number, component?: number}
没有多个接口的替代方案是
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: "" }
];
我在如何创建一个需要设置单个属性的Partial-like中问过类似的问题
上面的内容可以简化,但它可能更容易阅读,也可能不容易
export type MenuItem = {
title: string;
icon: string;
} & (
{component: any} | {click: string}
)
注意,这些都不会阻止你同时添加两者,因为TypeScript确实允许在使用AND/OR的对象上添加额外的属性,请参阅https://github.com/Microsoft/TypeScript/issues/15447
我用这个:
type RequireField<T, K extends keyof T> = T & Required<Pick<T, K>>
用法:
let a : RequireField<TypeA, "fieldA" | "fieldB">;
这使得fieldA和fieldB是必需的。
只是延伸到上面的酷答案!对于登陆这里的人,同时寻找一个需要能力的部分版本!这里有一个片段,我要采取!
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 RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
type MenuItem2 = RequiredKeys<MenuItem, "component" | "click">;