You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
IMO, even the strictest type systems tend to allow unsafe array indexing. I think the reason is that a type system should check things that are within its scope of being proven, but without going into the world of proof assistants and formal verification, virtually all array lookups cannot be proven to the type system to be within bounds, so the only practical result is that xs[i]! gets written everywhere instead, or lookups are done through a function that throws in the case of out-of-bounds.
In other words, there isn't any benefit having a type checker tell you that you failed to prove something without having any means of proving it.
+1 for this. I've been bitten by this compromise a couple times now so count me in for more safety not less!
the only practical result is that xs[i]! gets written everywhere instead
If folks are using an unsafe pattern everywhere, maybe that's exactly what should happen. I don't find it particularly onerous. I guess I'd like to see some data on exactly how much impact this would have on existing TypeScript programs before we write it off as making the language unusable.
how many real bugs it would find
how many false positives
how much it costs to annotate the false positives w/ ! (this could be automated for existing code)
Right now the sentiment I've seen from TS team is that 1 is negligible, 2 is huge, and 3 is prohibitive. Are there numbers to back up these hunches?
Some alternatives to ! proliferating:
Do undefined-checks on the result. This is the right thing to do in many cases!
Rewrite loops with for (let item of array) or array.forEach instead of for(let i = 0; i < array.length; i++).
Looping over a string[] array with for-of or forEach (or map, etc.) would never emit undefined, since each result is guaranteed to be in-bounds.
The same could be argued for Map<string,string>. map.get('foo') returns string | undefined, but map.set('foo', undefined) would be banned so that when looping over values with forEach or somesuch, you are guaranteed only to get string values, not string | undefined.
Reacted by Cyril Gandon, Jordan Van Walleghem, SlurpTheo, James Bromwell and Rafael Epplée
If authors enable strictNullChecking then they should expect some boilerplate overhead in return for increased safety. I'm surprised TypeScript isn't consistent in its approach here—as far as I know, this is the only scenario where the team has decided to go against type safety in favour of reduced boilerplate with regards to strictNullChecking?
I'm not too familiar with many other type systems, but Scala does have List.headOption which will return Option<T>, which would be the same thing as T | undefined in TypeScript.
Indeed there would be slightly more boilerplate if we did return T | undefined, as discussed above, but surely the job of the type system is to return the correct type, so the author can handle that correctly.
Without this there will be a whole class of bugs that TypeScript will never catch. 😒 😢
Reacted by Evan Winslow, SlurpTheo, James Bromwell, Lauri Lehmijoki, Sebastian "Sebbie" Silbermann, Denis Lepyohin, Mariusz Pawelski and Inaki Anduaga
Oliver Joseph Ash (@OliverJAsh) Scala is an interesting example but headOption is a way to get the first element in a collection that may or may not be empty instead of first checking if the collection is empty. But the result of headOption on some TraversableLike[T] is still an Option[T] so we are just deferring the check.
Consider the following Scala:
caseclassSomething(name: String)
varxs=Vector[Something]()
defunsafe= {
xs head
}
defsafe= {
xs headOption
}
println(safe match {
caseSome(s) => s name
case _ =>"explicit default"
})
println(unsafe name)
If you index into xs via xs(n) then you get T just like when you call head instead of headOption.
Activity
jesseschalken commentedon Sep 24, 2016
IMO, even the strictest type systems tend to allow unsafe array indexing. I think the reason is that a type system should check things that are within its scope of being proven, but without going into the world of proof assistants and formal verification, virtually all array lookups cannot be proven to the type system to be within bounds, so the only practical result is that
xs[i]!gets written everywhere instead, or lookups are done through a function that throws in the case of out-of-bounds.In other words, there isn't any benefit having a type checker tell you that you failed to prove something without having any means of proving it.
aluanhaddad commentedon Sep 24, 2016
Duplicate of #9235
See also #5203, 7140#issuecomment-192606629, #6229, and #9842
ewinslow commentedon Sep 24, 2016
+1 for this. I've been bitten by this compromise a couple times now so count me in for more safety not less!
If folks are using an unsafe pattern everywhere, maybe that's exactly what should happen. I don't find it particularly onerous. I guess I'd like to see some data on exactly how much impact this would have on existing TypeScript programs before we write it off as making the language unusable.
!(this could be automated for existing code)Right now the sentiment I've seen from TS team is that 1 is negligible, 2 is huge, and 3 is prohibitive. Are there numbers to back up these hunches?
Some alternatives to
!proliferating:for (let item of array)orarray.forEachinstead offor(let i = 0; i < array.length; i++).Looping over a
string[]array withfor-oforforEach(ormap, etc.) would never emit undefined, since each result is guaranteed to be in-bounds.The same could be argued for
Map<string,string>.map.get('foo')returnsstring | undefined, butmap.set('foo', undefined)would be banned so that when looping over values withforEachor somesuch, you are guaranteed only to getstringvalues, notstring | undefined.aluanhaddad commentedon Sep 24, 2016
+1000
mhegazy commentedon Sep 24, 2016
this indeed is a duplicate of #9235. thanks Aluan Haddad (@aluanhaddad).
As noted in #9235, this is an intentional behavior, and without this array access would be fairly unusable under
--strictNullChecks.OliverJAsh commentedon Sep 26, 2016
If authors enable
strictNullCheckingthen they should expect some boilerplate overhead in return for increased safety. I'm surprised TypeScript isn't consistent in its approach here—as far as I know, this is the only scenario where the team has decided to go against type safety in favour of reduced boilerplate with regards tostrictNullChecking?I'm not too familiar with many other type systems, but Scala does have
List.headOptionwhich will returnOption<T>, which would be the same thing asT | undefinedin TypeScript.Indeed there would be slightly more boilerplate if we did return
T | undefined, as discussed above, but surely the job of the type system is to return the correct type, so the author can handle that correctly.Without this there will be a whole class of bugs that TypeScript will never catch. 😒 😢
aluanhaddad commentedon Sep 26, 2016
Oliver Joseph Ash (@OliverJAsh) Scala is an interesting example but
headOptionis a way to get the first element in a collection that may or may not be empty instead of first checking if the collection is empty. But the result ofheadOptionon someTraversableLike[T]is still anOption[T]so we are just deferring the check.Consider the following Scala:
If you index into
xsviaxs(n)then you getTjust like when you callheadinstead ofheadOption.Edit:

OliverJAsh commentedon Oct 5, 2016
I'm currently working around this with a helper function:
Roaders commentedon Mar 29, 2018
it seems bizarre to me that this code is OK when pretty much all other possible errors are covered:
I vote for
firstItemhere to bestring | undefined