以下类型从输入类型的所有嵌套深度中删除所需的属性:
type DeepRemoveProps<T, P extends string> = T extends object
? { [K in Exclude<keyof T, P>]: DeepRemoveProps<T[K], P> }
: T;
例如:
type Input = {
a: {
b: string,
c: {
xx: 'removed',
d: string
}
},
yy: { removed: true },
xx: 'im removed'
};
type Result = DeepRemoveProps<Input, 'xx' | 'yy'>;
在这种情况下
Result
决定:
type Result = {
a: {
b: string,
c: {
d: string
}
}
};
但是这种类型无法保留字段是否可选!
例如,使用这种类型:
type Input = {
a: {
b?: string,
c: {
xx: 'removed',
d?: string
}
},
yy: { removed: true },
xx: 'im removed'
};
DeepRemoveProps<Input, 'xx' | 'yy'>
的结果与上面完全相同,具有所需的所有属性 - 由于某种原因,Input['a']['b']
和Input['a']['c']['d']
没有保留其?
。我的印象是 DeepRemoveProps
中使用的映射类型默认会保留 ?
是否存在。
如何以保留字段是否可选的方式实现
DeepRemoveProps
?
如果您希望映射类型保留要映射的属性的可选和
readonly
修饰符,则需要编写同态映射类型(请参阅“同态映射类型”是什么意思?) {[⋯ in keyof T]: ⋯}
表示 generic T
,其中 in keyof
直接出现。你有in Exclude<keyof
,它打破了它。 (TypeScript 需要知道原始类型是什么,以便复制属性修饰符。如果它看到 in keyof T
,它将了解您正在从 T
复制。但是,如果 in
之后设置的键是某种任意类型,则只是取决于在某处keyof T
,它不能确定。)
我的建议是使用 as
as
子句中的键,而不是
in
子句中的键。 也就是说,使用
Exclude
来作用于 K
而不是
keyof T
:
type DeepRemoveProps<T, P extends string> = T extends object ? {
[K in keyof T as Exclude<K, P>]: DeepRemoveProps<T[K], P>
} : T;
这会将与 K
重叠的任何键
P
映射到
never
,从而具有从输出中抑制该键的效果。 现在您的代码应该按预期运行:
type Result = DeepRemoveProps<Input, 'xx' | 'yy'>;
/* type Result = {
a: {
b?: string | undefined;
c: {
d?: string | undefined;
};
};
} */