映射的记录在递归时导致类型为any

时间:2019-03-24 03:56:50

标签: typescript

我正在使用映射类型转换数据结构,该结构可以按预期工作,除非有递归字段。

有没有办法防止它变成任何类型?

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

1 个答案:

答案 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

好的,希望能有所帮助。祝你好运!