英文:
TypeScript: Recursively retrieve field properties from class
问题
我试图使用这个答案在调用set
方法时排除函数,该方法本质上是类的字段,但我收到错误消息Type instantiation is excessively deep and possibly infinite.
我看到了这个问题,但我不能使用// @ts-ignore
,因为那样会失去类型安全性,并且接受的答案修改了它,以至于我不知道如何在我的示例中应用它。我还看到了这个问题,但再次,如何在这里应用有点令人困惑,可能是因为我不太理解TS递归泛型。如何递归检索字段属性(同时排除函数并考虑字段是否可选)而不会出现过多深度错误?
注意:链接代码中可能存在其他问题,因此我希望有经验的TS专家来修复它们。
Fiddle 和代码:
// types taken from https://stackoverflow.com/a/62362197/1253609
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]: T[P] extends Function ? never : 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]>;
};
class Base {
set(data?: Partial<DeepWritable<typeof this>>) {
Object.assign(this, data);
}
}
class Parent extends Base {
name?: string;
arr?: Parent[];
};
const record = new Parent();
record.set({
// https://github.com/microsoft/TypeScript/issues/34933
arr: [{
name: '0'
}]
})
console.log(record.arr);
英文:
I'm trying to use this answer to exclude functions from when I call the set
method with essentially the fields of the class, but I get the error Type instantiation is excessively deep and possibly infinite.
I saw this question, but I can't use // @ts-ignore
because I'll lose my type safety, and the accepted answer modifies it in such a way that I don't know how to apply in my example. I also saw this question, but once again, it's a little confusing how to apply here, probably due to my lack of understanding TS recursive generics. How do I recursively retrieve the field properties (while excluding functions and respecting if the fields are optional or not) and not get the excessively deep error?
Note: there might be some additional issues in the linked code, so I'm wishing for a seasoned TS expert to fix them.
Fiddle and code:
// types taken from https://stackoverflow.com/a/62362197/1253609
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]: T[P] extends Function ? never : 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]>
};
class Base {
set(data?: Partial<DeepWritable<typeof this>>) {
Object.assign(this, data);
}
}
class Parent extends Base {
name?: string;
arr?: Parent[];
};
const record = new Parent();
record.set({
// https://github.com/microsoft/TypeScript/issues/34933
arr: [{
name: '0'
}]
})
console.log(record.arr);
答案1
得分: 1
问题出现在递归部分,似乎是由于 Map
导致的,首先检查是否为 Map<any, any>
似乎可以解决它。您错过了失去可选性的键。
type DeepWritable1<T> =
| T extends DeepWritablePrimitive ? T
: T extends (infer U)[] ? DeepWritable1<U>[]
: T extends Map<any, any> ? (
T extends Map<infer K, infer V> ? Map<K, DeepWritable1<V>> : never
)
: T extends Set<infer V> ? Set<DeepWritable1<V>>
: DeepWritableRecord1<T>;
type DeepWritableRecord1<T> = {
// 需要保留可选性
[K in keyof Pick<T, WritableKeys<T>>]: DeepWritable1<T[K]>
}
英文:
Problem with recursion seems to be caused by Map
, checking for Map<any, any>
first seems to fix it.
You have missed keys losing optionality
type DeepWritable1<T> =
| T extends DeepWritablePrimitive ? T
: T extends (infer U)[] ? DeepWritable1<U>[]
: T extends Map<any, any> ? (
T extends Map<infer K, infer V> ? Map<K, DeepWritable1<V>> : never
)
: T extends Set<infer V> ? Set<DeepWritable1<V>>
: DeepWritableRecord1<T>;
type DeepWritableRecord1<T> = {
// need to keep optionality
[K in keyof Pick<T, WritableKeys<T>>]: DeepWritable1<T[K]>
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论