Debanik Dawn
Debanik Dawn

Reputation: 799

Object destructing resulting in 'never' type in TypeScript

My code is as follows:

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);
}

But this gives me the following error:

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)) });
                                          ~~~~~

I can't seem to understand why this is automatically inferring 'never' type. I tried explicitly declaring the type but to no luck.

Upvotes: 1

Views: 614

Answers (2)

Alex Wayne
Alex Wayne

Reputation: 187004

nodes = []. An array of what?

[] is never enough to for typescript to infer an array type, and is inferred as never[] in this particular case. So, typically, you just provide a type for the whole destructured object, and include the proper array type:

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

Or infer from the caller by using generics.

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

Note that you'll probably want to make Graph generic as well, so that the node type you pass to testGraph can be reflected in the Graph's nodes as well.

That might look something like:

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

Upvotes: 1

Nishant
Nishant

Reputation: 55856

This discussion on Github puts some light on the issue:

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.

So, this may be a possible way out

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

Upvotes: 1

Related Questions