5

I get TS error:

TypeScript error: Type 'undefined' cannot be used as an index type. TS2538

For this simple function (getting object from array based on provided index):

const myArr: Array<object> = [{name: 'John'}, {name: 'Tom'}]

function getData(index?: number) {
    const isIndex : boolean = typeof index !== 'undefined';

    return isIndex ? myArr[index] : {};
}

What's more mysterious for me is that when I change it to:

function getData(index?: number) {
    return typeof index !== 'undefined' ? myArr[index] : {};
}

Everything works like a charm - why?

jepek
  • 160
  • 2
  • 6
  • 2
    It seems to be a problem with extrapolating the code path. In the latter case it's absolutely clear that if `index` is `undefined`, then you would not take the code path that does `myArr[index]`. When you introduce the level of indirection from the first example, it's not immediately clear that `myArr[index]` will not be called when `index` is `undefined`. – VLAZ May 29 '19 at 07:26
  • 2
    This is the way code analysis works, if you do the check inline it can follow the logic and narrow the variable if you put it in a variable it will not be able to follow the logic. – Titian Cernicova-Dragomir May 29 '19 at 07:41

2 Answers2

0

Due to some indirection in the code flow, Typescript won't follow code analysis as we expect. so this is where User Defined Type Guards comes into the picture to rescue.

function isUndefined(index: any): index is boolean {
    return typeof index === "undefined";
}

function getData(index?: number) {
    return isUndefined(index) ? myArr[index] : {};
}

Because index is optional in getData function so it's possibly be undefined, so your second approach works.

Raja Jaganathan
  • 22,671
  • 4
  • 22
  • 30
0

Type guards don't work with intermediate variables. You have to directly test the variable:

function getData(index?: number) {
  return index !== undefined ? myArr[index] : {};
}

Or:

function getData(index?: number) {
  if (index === undefined)
    return {};
  return myArr[index]
}

See also: documentation from the handbook on type guards.

Notice: typeof index !== 'undefined' is not required nowadays: ES2015/2016 way of 'typeof varName === 'undefined`?

Paleo
  • 16,013
  • 3
  • 44
  • 62
  • `typeof index !== 'undefined'` is not even needed here. The variable `index` is *by definition* present - you'd want to do the `typeof` check to avoid referencing an undefined variable. The other problem that `typeof` solves is `undefined` is...not actually the value `undefined`. I'd say that if you have *that* problem, then there is something bigger that's amiss and `typeof` is just treating the symptom, not the problem. – VLAZ May 29 '19 at 09:30
  • As a side note, you can still redefine `undefined` even with strict mode. I was surprised to find this out, honestly. `test = undefined => "a" == undefined` and then try calling `test("a")` – VLAZ May 29 '19 at 09:33
  • @VLAZ My bad it is since ES2015. Yes you can name a parameter `undefined` but it is just a bad practice. The user of your API can't change your `undefined`, it is enough to write strong code. – Paleo May 29 '19 at 11:00