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
{{ message }}
Repository navigation
TS fails to understand guard for Array.prototype.pop() #30406
you just need an interface that represents a non-empty array and a type guard function:
constarr: string[]=[];interfaceNonEmptyArray<T>extendsArray<T>{// would need to implement all relevant functions.pop: ()=>T;}functionisNonEmpty<T>(arr: Array<T>): arr is NonEmptyArray<T>{returnarr.length>0;}if(isNonEmpty(arr)){// here we are sure arr.pop() will return a value!arr.pop().toLowerCase();}
Edit: never mind, in the general case there really isn't any way to ensure pop is valid since if you pop more than once this would still act like each one was guaranteed not to return undefined, so this doesn't get caught by typescript:
if(isNonEmpty(arr)){arr.clear();// typescript still under assertion that arr isn't empty!arr.pop().toLowerCase();}
Reacted by Ricardo Fernández Serrata
Reacted by Timur Fayzrakhmanov, frankda, shudagao and Dylan Greene
Reacted by Alexander Skrivanos, sudhakarg1990, Eddy Hernández, Mahmoud Swehli, wbt and frankda
Reacted by Kirill Agalakov, Nikolay Kudryavtsev, Alexander, Per Thomasson, Timur Fayzrakhmanov, Dylan Greene, Daniel Sheward, Jan Romann, Thomas Gak-Deluen, Ricardo Fernández Serrata and 1 more
Reacted by Bas van Meurs, Lucy Bain, Audun Skjervold, Bernard and Ricardo Fernández Serrata
Reacted by Kirill Agalakov, Alexander, Per Thomasson, Timur Fayzrakhmanov, Dylan Greene, Daniel Sheward, Thomas Gak-Deluen and Ricardo Fernández Serrata
classStack<T>{privatedata: T[]=[];constructor(){}push(item: T): void{this.data.push(item);}pop(): T|0{if(this.data.length>0)returnthis.data.pop();// Error : Type 'undefined' is not assignable to type '0 | T'.elsereturn0;}}
EDIT: below code has no problem. Weird i think.
classStack<T>{privatedata: T[]=[];constructor(){}push(item: T): void{this.data.push(item);}pop(): T{returnthis.data[this.data.length];// no error but it could actually return 'undefined'}}
TypeScript already recognizes an index signature property type which must be either ‘string’ or ‘number’. In addition to that, TypeScript could keep track of minLength and maxLength as part of an Array-like's type definition, which changes dynamically through operations like push/pop/shift/unshift/splice etc. Unless otherwise specified or guarded, the default is minLength 0 and maxLength of the largest UINT32. Then you could do things like this:
if(arr.length>0){//guard: arr.minLength is now 1arr.pop().toLowerCase();//this would be fine; arr.minLength drops by 1 to 0arr.pop().toLowerCase();//this second call would have a type error, fixed by setting 0 to 1 in check.}
Though it is not a trivial implementation, I think Typescript would be much more useful with that enhancement.
Activity
jack-williams commentedon Mar 14, 2019
I think is essentially the same thing as #9619, or rather, it suffers from the same limitations.
RyanCavanaugh commentedon Mar 14, 2019
This isn't something we're capable of tracking
tadhgmister commentedon Mar 17, 2019
you just need an interface that represents a non-empty array and a type guard function:
Edit: never mind, in the general case there really isn't any way to ensure pop is valid since if you pop more than once this would still act like each one was guaranteed not to return undefined, so this doesn't get caught by typescript:
MartinJohns commentedon Mar 23, 2019
Tadhg McDonald-Jensen (@tadhgmister) This would require something like #29346, #27568, #25679, #8655, #10421. A way to indicate that a function will mutate and change the type of an argument.
basvanmeurs commentedon Aug 6, 2019
A simple way to let Typescript know that it can assume 'not undefined' is to use an explicit cast:
dragomirtitian commentedon Aug 6, 2019
Bas van Meurs (@basvanmeurs) A not null assertion:
roeniss commentedon May 16, 2020
Is this relevant?
EDIT: below code has no problem. Weird i think.
wbt commentedon Feb 14, 2022
TypeScript already recognizes an index signature property type which must be either ‘string’ or ‘number’. In addition to that, TypeScript could keep track of
minLengthandmaxLengthas part of an Array-like's type definition, which changes dynamically through operations like push/pop/shift/unshift/splice etc. Unless otherwise specified or guarded, the default is minLength 0 and maxLength of the largest UINT32. Then you could do things like this:Though it is not a trivial implementation, I think Typescript would be much more useful with that enhancement.
Rudxain commentedon Nov 12, 2024
Related: #31376