我有一个这样的界面:
export interface Campaign {
id: string
orders?: number
avgOrderValue?: number
optionalAttributes: string[]
attributeValues: {
optionalAttributes: CampaignAttribute[]
mandatoryAttributes: CampaignAttribute[]
values?: { [key: string]: unknown }
}
created: number
lastUpdated: number
}
我想为我的表单创建一个类型,需要从界面中省略 attributeValues.optionalAttributes
和 attributeValues.mandatoryAttributes
。
我在想也许 Typescript 可以做这样的事情:
export type CampaignFormValues = Omit<Campaign, 'attributeValues.mandatoryAttributes'>
但这不起作用。
我使用了这个问题的答案:Deep Omit with typescript 但是这个答案只是深深地省略了每个匹配的键,所以像这样使用它:
export type CampaignFormValues = Omit<Campaign, 'optionalAttributes'>
还会删除我想保留的根级别 optionalAttributes
。
有没有办法用 Typescript 做嵌套省略?
答案 0 :(得分:1)
type A = {
a: {
b: string
c: string
}
x: {
y: number
z: number,
w: {
u: number
}
}
}
type Primitives = string | number | boolean | symbol
/**
* Get all valid nested pathes of object
*/
type AllProps<Obj, Cache extends Array<Primitives> = []> =
Obj extends Primitives ? Cache : {
[Prop in keyof Obj]:
| [...Cache, Prop] // <------ it should be unionized with recursion call
| AllProps<Obj[Prop], [...Cache, Prop]>
}[keyof Obj]
type Head<T extends ReadonlyArray<any>> =
T extends []
? never
: T extends [infer Head]
? Head
: T extends [infer Head, ...infer _]
? Head
: never
type Tail<T extends ReadonlyArray<any>> =
T extends []
? []
: T extends [infer _]
? []
: T extends [infer _, ...infer Rest]
? Rest
: never
type Last<T extends ReadonlyArray<any>> = T['length'] extends 1 ? true : false
type OmitBase<Obj, Path extends ReadonlyArray<any>> =
Last<Path> extends true
? {
[Prop in Exclude<keyof Obj, Head<Path>>]: Obj[Prop]
} : {
[Prop in keyof Obj]: OmitBase<Obj[Prop], Tail<Path>>
}
// we should allow only existing properties in right order
type OmitBy<Obj, Keys extends AllProps<Obj>> = OmitBase<A, Keys>
type Result = OmitBy<A,['a', 'b']> // ok
type Result2 = OmitBy<A,['b']> // expected error. order should be preserved
More explanation 你可以在我的博客中找到
以上解决方案适用于深层嵌套类型
如果您想使用点语法 prop1.prop2
,请考虑下一种类型:
type Split<Str, Cache extends string[] = []> =
Str extends `${infer Method}.${infer Rest}`
? Split<Rest, [...Cache, Method]>
: Str extends `${infer Last}`
? [...Cache, Last,]
: never
type WithDots = OmitBy<A, Split<'a.b'>> // ok
答案 1 :(得分:0)
您需要创建一个覆盖 attributeValues
的新界面:
export interface Campaign {
id: string
orders?: number
avgOrderValue?: number
optionalAttributes: string[]
attributeValues: {
optionalAttributes: CampaignAttribute[]
mandatoryAttributes: CampaignAttribute[]
values?: { [key: string]: unknown }
}
created: number
lastUpdated: number
}
interface MyOtherCampaign extends Omit<Campaign, 'attributeValues'> {
attributeValues: {
values?: { [key: string]: unknown }
}
}
let x:MyOtherCampaign;
答案 2 :(得分:0)
首先,省略 attributeValues
,然后将其添加回来并删除属性。
export interface Campaign {
id: string
attributeValues: {
optionalAttributes: string[]
mandatoryAttributes: string[]
values?: { [key: string]: unknown }
}
}
type ChangeFields<T, R> = Omit<T, keyof R> & R;
type CampaignForm = ChangeFields<Campaign, {
attributeValues: Omit<Campaign['attributeValues'], 'mandatoryAttributes'|'optionalAttributes'>
}>;
const form: CampaignForm = {
id: '123',
attributeValues: {
values: { '1': 1 }
}
}