我正在使用映射类型转换数据结构,该结构可以按预期工作,除非有递归字段。
有没有办法防止它变成任何类型?
type DataType<T extends Record<keyof T, Obj<any, any>>> = {
[P in keyof T]: T[P]['data']
}
// I need to be able to pass in a Data generic
// to this object
class Obj<
Data extends DataType<T>,
T extends Record<keyof Data, Obj<any, any>>
> {
constructor(public fields: T) {}
public data: Data
}
const recursive = new Obj({
// With this field, the 'recursive' variable becomes type 'any'
get query() {
return recursive
},
test: new Obj({})
})
// Without recursive field it works as expected
const nonRecursive = new Obj({ test: new Obj({}) })
nonRecursive.data.test // okay
答案 0 :(得分:2)
嗯,您在这里携带了许多相互参照的泛型类型,并且没有用例和示例,我承认我几乎不知道这里发生了什么,如果这确实是表示数据结构的最佳方式, 。我猜您可能可以摆脱像这样的单个类型参数:
class Obj<T>
{
constructor(public fields: { [K in keyof T]: Obj<T[K]> }) {
}
public data!: T
}
但是,即使您这样做,仍然会遇到相同的问题,如果启用了严格的compiler options(例如--noImplicitAny
或--strict
,则会暴露该问题。然后,您将看到recursive
的定义给您带来以下错误:
'recursive' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
和
'query' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
这是intended behavior,当编译器无法推断类型时,因为它以某种方式依赖于自身。解决此问题的建议方法通常是为其中一个片段提供显式类型注释,以打破圆度。这很烦人,因为它迫使您将类型重复写入以前由编译器推断的内容,但是我不知道是否有避免这种情况的好方法。
这里是对类型进行处理的一种方法:
// explicit type
interface RecursiveObj extends Obj<
DataType<
{ readonly query: RecursiveObj; test: Obj<{}, {}>; }
>, { readonly query: RecursiveObj; test: Obj<{}, {}>; }> {
}
const recursive = new Obj({
// explicitly annotated return type
get query(): RecursiveObj {
return recursive
},
test: new Obj({})
}); // okay now
这是我上面列出的简化Obj<T>
类型的处理方式:
// explicit type
interface RecursiveData {
readonly query: RecursiveData,
test: {}
}
const recursive = new Obj({
// explicitly annotated return type
get query(): Obj<RecursiveData> {
return recursive
},
test: new Obj({})
}); // okay now
好的,希望能有所帮助。祝你好运!