对象破坏导致 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,nodes);
}
export function testDatabase({ id = 0,graphs = [] }): Database {
  if (graphs.length === 0) {
    const dummyGraph = testGraph({ nodes: new Array(new Node(0)) });
    return new Database(id,[dummyGraph]);
  }

  return new Database(id,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)) });
                                          ~~~~~

我似乎无法理解为什么这会自动推断“从不”类型。我尝试明确声明类型,但没有运气。

解决方法

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

这是由 strictnoImplicitAny: false 的组合引起的。一般来说,我们期望如果 strict 打开,noImplicitAny 也打开;这组特定的设置会暴露一些奇怪的行为。如果两者都打开,您会看到关于 [] 被隐式 any[]; 的错误。如果两者都关闭;我们将使用控制流分析并将数组视为 push(1); 之后的 number[]

设置的特定组合 ( "strict": true,"noImplicitAny": false, ) 意味着我们不允许自己使用控制流分析或允许数组隐式 any[],因此 never[] 是唯一的剩余的允许选项。

如果您不打算打开 strict,我建议您关闭 noImplicitAny

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

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

,

nodes = []。什么数组?

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

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

或者使用 generics 从调用者推断。

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

请注意,您可能还希望将 Graph 设为泛型,以便您传递给 testGraph 的节点类型也可以反映在 Graph 的节点中。

这可能看起来像:

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...