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
type guard narrowing to a type with type with any in type parameters replaces any with unknown #57892
Likely this is working as intended. There is a subtype relationship between Box<unknown> is a strict subtype of Box<any> and thus it's preferred when narrowing here. If the predicate's type would be preferred here then you would end up with Box<any> here and that's not desirable:
interfaceBox<T>{value: T;}functionisBox(box: unknown): box is Box<any>{returntrue;}declareclassDog{bark(): void;}declareconstsmth: Box<number>|Dog;if(isBox(smth)){smth.value;// ^? Box<number>}
Narrowing is more like a filtering operation and not like a cast/assignment. Otherwise, you likely wouldn't be able to express "check if it's a Box and if it's a Box keep the type intact". We can check how this doesn't infer the type argument:
interfaceBox<T>{value: T;}functionisBox<T>(box: unknown): box is Box<T>{returntrue;}declareclassDog{bark(): void;}declareconstsmth: Box<number>|Dog;if(isBox(smth)){// ^? function isBox<unknown>(box: unknown): box is Box<unknown>smth.value;// ^? Box<number>}
If the type guard is typed as box is Box<any> then the any is clearly desired.
It really isn't. People in general hate any appearing in their code unless it's via some extremely direct incantation.
This has been the behavior since at least 3.3 and I don't think this is a) surprising, since we haven't gotten other reports on it or b) a welcome change to all the people who wrote declarations of the form is F<any> when they maybe should have written is F<unknown> but will now see an infectious any they didn't want.
note that IIRC Array.isArray(x) is typed as x is Array<any> - and obviously you don't want your values typed as e.g. number[] | number to be "narrowed" to any[]
Activity
Andarist commentedon Mar 21, 2024
Likely this is working as intended. There is a subtype relationship between
Box<unknown>is a strict subtype ofBox<any>and thus it's preferred when narrowing here. If the predicate's type would be preferred here then you would end up withBox<any>here and that's not desirable:eps1lon commentedon Mar 21, 2024
If the type guard is typed as
box is Box<any>then theanyis clearly desired.It's fine if TypeScript tries to guess missing intent. But here we authored it as "narrow this to
any" so TypeScript shouldn't override it.Andarist commentedon Mar 21, 2024
Narrowing is more like a filtering operation and not like a cast/assignment. Otherwise, you likely wouldn't be able to express "check if it's a Box and if it's a Box keep the type intact". We can check how this doesn't infer the type argument:
RyanCavanaugh commentedon Mar 21, 2024
It really isn't. People in general hate
anyappearing in their code unless it's via some extremely direct incantation.This has been the behavior since at least 3.3 and I don't think this is a) surprising, since we haven't gotten other reports on it or b) a welcome change to all the people who wrote declarations of the form
is F<any>when they maybe should have writtenis F<unknown>but will now see an infectiousanythey didn't want.RyanCavanaugh commentedon Mar 21, 2024
I missed the regression part since I think I was working off the other example. I'll bisect to ensure we're on the same page here.
RyanCavanaugh commentedon Mar 21, 2024
Yeah, the 4.9.5 behavior is just inconsistent for no obvious reason:
It doesn't make sense to narrow from
unknowntoanybut not any of the other types.fatcerberus commentedon Mar 22, 2024
note that IIRC
Array.isArray(x)is typed asx is Array<any>- and obviously you don't want your values typed as e.g.number[] | numberto be "narrowed" toany[]typescript-bot commentedon Mar 25, 2024
This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.