MatasLiu
MatasLiu

Reputation: 59

Typescript complains about variable types after array destructuring

I have a function

function foo() {
    return ["", 1, () => ""];
}

types are: string, number and (() => string)

however after I destructure those values

const [str, num, func] = foo();

compiler treats each variable as type: string | number | (() => string)

I want to pass these variables in functions, but compiler complains that types don't match and my IDE goes nuts with red text underlying. What can I do?

Upvotes: 3

Views: 1122

Answers (3)

Pritam Kadam
Pritam Kadam

Reputation: 2527

Another way to achieve this is:

function foo() {
  return ['', 1, () => ''] as const
}

const [str, num, func] = foo()

Main difference with as const and without it is that:

  • as const tells ts that it is immutable value, hence ts infers concrete type which in this case is tuple of 3, and as you know, tuple can have different types
  • without as const, ts infers it as Array and array takes single type parameter, but in this case array is holding string, number and func values. Hence ts infers it as (string | number | () -> string)[]

Upvotes: 6

Curtis Fenner
Curtis Fenner

Reputation: 1403

By default, TypeScript infers the type of an array literal not as a tuple, but as an array of a union of all of the element types. So in const x = [a, b, c]; isn't inferred to have type [A, B, C] but instead (A | B | C)[].

If you want TypeScript to infer a tuple type, you have to explicitly indicate that:

const x: [A, B, C] = [a, b, c]; // this typechecks

An alternative is to use the as const syntax:

const x = [a, b, c] as const; // infers as `readonly [A, B, C]`

This isn't the only place where TypeScript infers a less-specific type than seems possible. For example, string literals by default infer as string instead of their literal type: let x = "word"; // string vs let x = "word" as const; // "word" vs const x = "word"; // "word"

Upvotes: 5

Owl
Owl

Reputation: 6853

Specify the return type of the function

function foo(): [string, number, () => string] {
    return ["", 1, () => ""];
}

This will strictly type the function to return an array with:

  • value of index 0 to be type string
  • value of index 1 to be type number
  • value of index 2 to be type () => string / function that returns string
function foo(): [string, number, () => string] {
    return [0, 1, () => ""]; // Will shows error because index 0 is number, not string
}

Upvotes: 9

Related Questions