7

Ignore the fact that this is bad add function. It's a question about using array destructuring with spread syntax in TypeScript.

This is what I'm trying

const add = ([x,...xs]) => {
  if (x === undefined)
    return 0
  else
    return x + add(xs)
}

console.log(add([1,2,3])) //=> 6

But I have no idea how to add TypeScript types to this. My best guess is to do something like this (most direct translation)

const add = (xs: number[]): number => {
  if (xs[0] === undefined)
    return 0;
  else
    return xs[0] + add(xs.slice(1));
};

console.log(add([1,2,3])); // => 6

Both functions work, but in TypeScript I lose the ability to destructure the array parameter and the function body is junked up with a bunch of ugly stuff like xs[0] and xs.slice(1) – even if I abstract these into their own functions, that's besides the point.

Is it possible in add types to destructured spread parameters in TypeScript?


What I've tried so far

Something like this works for fixed arrays

// compiles
const add = ([x,y,z]: [number, number, number]): number => ...

But of course I need variable length array input. I tried this, but it doesn't compile

// does not compile
const add = ([x, ...xs]: [number, number[]]): number => ...
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • Theoretically what you're saying should work using the spread operator... https://basarat.gitbooks.io/typescript/content/docs/spread-operator.html. Oh, you want to add types... I just read the rest of this – djthoms Feb 18 '17 at 23:56
  • Yeah, I found that too – I don't know enough about TypeScript, but I thought that was a really strange page to have in that book. I mean, who cares about these features in TypeScript if you can't use them with *types* ... – Mulan Feb 19 '17 at 00:02
  • I don't think this is supported with spread. If the array if of fixed length you can do: `[x, y, z]: [number, number, number]` but that's it :( – djthoms Feb 19 '17 at 00:11
  • Yeah, I tried something similar. I'll update my question to help people that might waste time in a similar fashion. – Mulan Feb 19 '17 at 00:13

1 Answers1

5

My bad, the answer is as simple as:

const add = ([x, ...xs]: number[]) => {
  if (x === undefined)
    return 0
  else
    return x + add(xs)
}

console.log(add([1, 2, 3])); //=> 6
add(["", 4]); // error

(code in playground)


Original answer:

You can do this:

const add: (nums: number[]) => number = ([x, ...xs]) => {
    if (x === undefined)
        return 0
    else
        return x + add(xs)
}

You can also use a type alias:

type AddFunction = (nums: number[]) => number;

const add: AddFunction = ([x, ...xs]) => {
    ...
}
Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • guh... that is *so* fricken awkward – especially because we must provide a name for the type (in this case `nums`). it's so counter-intuitive because `nums` is an identifier that's not actually available in the scope of `add`. It bothers me to no end that [TypeScript forces you to specify identifiers that aren't usable](http://stackoverflow.com/q/42322251/633183). Anyway, thanks for providing a solution for this. -1 for TypeScript, +1 for you. – Mulan Feb 19 '17 at 01:02
  • Well, I did not completely understand you. Check my revised answer. – Nitzan Tomer Feb 19 '17 at 01:10
  • OK, redemption number 1! Thanks heaps. I'd be thrilled to have you look at that other question to let me know if there's a redemption number 2 ^_^ – Mulan Feb 19 '17 at 01:19