对象解构导致 TypeScript 中的 'never' 类型

Object destructing resulting in 'never' type in TypeScript

我的代码如下:

export function testGraph({ id = 0, name = "test", nodes = [] }): Graph {
  if (nodes.length === 0) {
    const dummyNode = testNode({});
    return new Graph(id, name, [dummyNode]);
  }

  return new Graph(id, name, nodes);
}
export function testDatabase({ id = 0, name = "test", graphs = [] }): Database {
  if (graphs.length === 0) {
    const dummyGraph = testGraph({ nodes: new Array(new Node(0)) });
    return new Database(id, name, [dummyGraph]);
  }

  return new Database(id, name, graphs);
}

但这给了我以下错误:

Type 'Node[]' is not assignable to type 'never[]'.
      Type 'Node' is not assignable to type 'never'.

    40     const dummyGraph = testGraph({ nodes: new Array(new Node(0)) });
                                          ~~~~~

我似乎无法理解为什么这是自动推断 'never' 类型。我尝试明确声明类型但没有成功。

This discussion on Github 阐明了这个问题:

This is caused by the combination of strict and noImplicitAny: false. In general we expect that if strict is on, noImplicitAny is also on; this particular set of settings will expose some odd behavior. If you had both on, you'd see an error about the [] being implicitly any[]; if both were off; we'd use control flow analysis and treat the array as a number[] after the push(1);.

The particular combination ( "strict": true, "noImplicitAny": false, ) of settings means that we don't allow ourselves to use control flow analysis or allow the array to be implicitly any[], so never[] is the only remaining allowable option.

I'd recommend turning off strict if you're not going to have noImplicitAny on.

所以,这可能是一个可行的出路

export function testGraph({ id = 0, name = "test", nodes = [] as Array<Node> }): Graph {
...

nodes = []。什么数组?

[] 永远不足以让打字稿推断数组类型,在这种特殊情况下被推断为 never[] 。因此,通常情况下,您只需为整个解构对象提供一个类型,并包括适当的数组类型:

export function testGraph({
    id = 0,
    name = "test",
    nodes = []
}: {
    id?: number,
    name?: string,
    nodes?: Node[]
}): Graph {
    //...
}

或使用generics从调用者推断。

export function testGraph<T>({
    id = 0,
    name = "test",
    nodes = []
}: {
    id?: number,
    name?: string,
    nodes?: T[]
}): Graph<T> {
    //...
}

请注意,您可能还想使 Graph 通用,以便您传递给 testGraph 的节点类型可以反映在 Graph 的节点中嗯

这可能看起来像:

class Graph<T> {
    constructor(id: number, name: string, nodes: T[]) {
        //...
    }
}