The whole point of adding static types to JavaScript is to provide some guarantees about type safety. I noticed that array indexing seems to break type safety without using any dirty tricks like as any
or the not null assertion operator.
let a: Array<number> = [1,2,3,4];
let b: number = a[4]; //undefined
This code does not cause any TypeScript errors, even though it is plain to see that it will violate type safety. It seems to me that the type of an Array<T>
acted upon by the index operator []
should be type T | undefined
, however the TypeScript piler treats it as if it was type T
.
Upon further investigation, I discovered that this behavior applies to use of the index operator on objects as well. It would seem that the index operator is not type safe in any case.
class Example {
property: string;
}
let c: Example = { property: "example string" }
let d: string = c["Not a property name"]; //undefined
Use of the index operator on an object with arbitrary key returns type any
, which can be assigned to any type without causing type errors. However, this can be resolved by using the --noImplicitAny
piler option.
My question is why does something as basic as indexing on an array break type safety? Is this a design constraint, an oversight, or a deliberate part of TypeScript?
The whole point of adding static types to JavaScript is to provide some guarantees about type safety. I noticed that array indexing seems to break type safety without using any dirty tricks like as any
or the not null assertion operator.
let a: Array<number> = [1,2,3,4];
let b: number = a[4]; //undefined
This code does not cause any TypeScript errors, even though it is plain to see that it will violate type safety. It seems to me that the type of an Array<T>
acted upon by the index operator []
should be type T | undefined
, however the TypeScript piler treats it as if it was type T
.
Upon further investigation, I discovered that this behavior applies to use of the index operator on objects as well. It would seem that the index operator is not type safe in any case.
class Example {
property: string;
}
let c: Example = { property: "example string" }
let d: string = c["Not a property name"]; //undefined
Use of the index operator on an object with arbitrary key returns type any
, which can be assigned to any type without causing type errors. However, this can be resolved by using the --noImplicitAny
piler option.
My question is why does something as basic as indexing on an array break type safety? Is this a design constraint, an oversight, or a deliberate part of TypeScript?
Share Improve this question asked Aug 8, 2017 at 18:27 Robert StifflerRobert Stiffler 7254 silver badges10 bronze badges 4- 2 That's an open issue. Please follow the discussion on github and let them know if you have any further ideas on this. – dotcs Commented Aug 8, 2017 at 18:35
- It is an intentional work around because Javascript objects are not actually typed classes in the way Typescript likes to treat them. I have had to use this method several time when I receive back an object that I know may have had additional properties added by another function. – Ray Suelzer Commented Aug 8, 2017 at 20:37
- I wrote a workaround: github./danielnixon/total-functions – danielnixon Commented Sep 30, 2019 at 1:51
-
1
Thankfully Array.at behaves as you might expect, returning
T | undefined
– nireno Commented Apr 27, 2023 at 19:23
3 Answers
Reset to default 6Since Typescript version 4.1 we have the setting noUncheckedIndexedAccess. Enabling this basically works like what you describe - the inferred type of index access always includes undefined
. In your example, the type of b
bees T | undefined
.
To answer the why part of your question, it is because the developers of TypeScript thought that it would be too unfortable if you always had to check for undefined
results when indexing an Array
.
For example, the following code would not type-check:
var arr: number[]
var s = 0
for (var i in arr) {
s += arr[i]
}
Furthermore, because JavaScript Array
s can be sparse, even if the index is known to not be out of bounds (as in, >= 0
and < arr.length
), you can still get undefined
, so there seems to be no way to fully infer actual unsafe indexing.
For more on this, see the issues TypeScript#13778 and TypeScript#11122.
Use of the index operator on an object with arbitrary key returns type any, which can be assigned to any type without causing type errors. However, this can be resolved by using the --noImplicitAny piler option.
Yes. Use the noImplicitAny
, if you care for strict safety. Also strict:true
(which strictNullChecks
as well as others).
My question is why does something as basic as indexing on an array break type safety? Is this a design constraint, an oversight, or a deliberate part of TypeScript?
There are levels of safety. strict
is the strongest. You choose how strict you want to be with your code.
More
From https://basarat.gitbooks.io/typescript/content/docs/options/intro.html
That said, traditionally programming languages have a hard boundary between what is and isn't allowed by the type system. TypeScript is different in that it gives you control on where you put the slider.