递归排除 Typescript 中的只读属性
Posted
技术标签:
【中文标题】递归排除 Typescript 中的只读属性【英文标题】:Recursively exclude readonly properties in Typescript 【发布时间】:2020-10-03 06:52:10 【问题描述】:我很确定我缺乏使用复杂泛型的经验,所以我希望有人对如何实现这一点有想法。我的用例是为我的 React/Formik 表单值创建“表单类型”,而无需重新键入新定义或传入具有许多不可更新属性的完整对象。
我找到了这个答案,它展示了如何从 TypeScript 类型中排除只读属性,但我发现很难将我的大脑包裹起来使其递归。此外,我希望它省略返回空嵌套对象的属性(如果可能)。
How to exclude getter only properties from type in typescript
type IfEquals<X, Y, A=X, B=never> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? A : B;
type WritableKeys<T> =
[P in keyof T]-?: IfEquals< [Q in P]: T[P] , -readonly [Q in P]: T[P] , P>
[keyof T];
type ReadonlyKeys<T> =
[P in keyof T]-?: IfEquals< [Q in P]: T[P] , -readonly [Q in P]: T[P] , never, P>
[keyof T];
type Writable<T> = Pick<T, WritableKeys<T>>
type Brand =
readonly id: number;
name: string;
logo:
readonly id: number;
url: string;
,
creator:
readonly id: number;
;
type EditableBrand = Writable<Brand>;
// type EditableBrand =
// name: string;
// logo:
// url: string;
//
// ;
【问题讨论】:
【参考方案1】:TypeScript 存储库中有一个 suggestion 用于 DeepReadonly<T>
类型,还有一些建议的实现。和 *** 上的 question 相同。 Here。是如何实现DeepReadonly
的示例。您可以使用相同的技术来实现DeepWritable
类型:
type IfEquals<X, Y, A=X, B=never> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? A : B;
type WritableKeys<T> =
[P in keyof T]: IfEquals< [Q in P]: T[P] , -readonly [Q in P]: T[P] , P>
[keyof T];
type DeepWritablePrimitive = undefined | null | boolean | string | number | Function;
type DeepWritable<T> =
T extends DeepWritablePrimitive ? T :
T extends Array<infer U> ? DeepWritableArray<U> :
T extends Map<infer K, infer V> ? DeepWritableMap<K, V> :
T extends Set<infer T> ? DeepWriableSet<T> : DeepWritableObject<T>;
type DeepWritableArray<T> = Array<DeepWritable<T>>;
type DeepWritableMap<K, V> = Map<K, DeepWritable<V>>;
type DeepWriableSet<T> = Set<DeepWritable<T>>;
type DeepWritableObject<T> =
[K in WritableKeys<T>]: DeepWritable<T[K]>
;
Playground
让我们扩展类型以省略返回空嵌套对象的键:
...
type EmptyKeys<T> =
[P in keyof T]: extends T[P] ? P : never
[keyof T];
type OmitEmptyKeys<T> = Omit<T, EmptyKeys<T>>;
type DeepWritable<T> = ... : OmitEmptyKeys<DeepWritableObject<T>>;
Playground
【讨论】:
这非常有帮助。谢谢! @ericchernuka 很高兴为您提供帮助!点赞是最好的奖励:)以上是关于递归排除 Typescript 中的只读属性的主要内容,如果未能解决你的问题,请参考以下文章