Not planned
Description
π Search Terms
type guard parameter any unknown
π Version & Regression Information
- This changed between versions 4.9.6 and 5.0.4
β― Playground Link
π» Code
interface Box<T> {
value: T
}
function isBox<T>(box: unknown): box is Box<T> {
return true
}
const numberBox: Box<unknown> = {value:1}
if (isBox<number>(numberBox)) {
numberBox.value
// ^?
}
if (isBox<any>(numberBox)) {
numberBox.value
// ^?
}
π Actual behavior
if (isBox<any>(numberBox)) {
numberBox.value
// ^? (property) Box<unknown>.value: unknown
}
π Expected behavior
if (isBox<any>(numberBox)) {
numberBox.value
// ^? (property) Box<any>.value: any
}
Additional information about the issue
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
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 theany
is 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
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 writtenis F<unknown>
but will now see an infectiousany
they 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
unknown
toany
but 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[] | number
to 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.