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 narrowing generics/unknown doesn't seem to work with typeof and null checkΒ #43997
The generic function doesn't infer that obj must be an object of some sort.
The first if doesn't infer that testVariable can't be null.
π Expected behavior
The generic function should infer that T is an object because we did a null check and checked typeof.
Both ifs should infer that testVariable can't be null.
Notes
Is this just me missing some 'known behaviour' typescript has? the two conditions seem to depend on ordering, maybe thats just a known thing i was unaware of (i.e. by design)?
The second part of this is. There are two issues i would say, the generic function can be re-ordered to have the same order and will still error.
e.g.
functionfunc<T>(obj: T): boolean{// Errors because `hasOwnProperty` doesn't exist on T, doesn't know it is an objectif((typeofobj==='object')&&obj!==null&&obj.hasOwnProperty('xyz')){returntrue;}returnfalse;}
so why is it any different just because we have a T rather than unknown? which is just as lacking in type
i suppose because T means the compiler could have inferred the type from higher up the chain and would know hasOwnProperty is something different here, whereas with unknown it really has no clue so is a bit dumber about it. so only because the compiler knows more in the case of generics it disallows this
I don't know about the specifics, you'd need to wait for the TypeScript team or someone else more knowledgable.
But your guess sounds like a good one to me. It's similar to this example:
function func<T extends Object>(value: T) {
if (isTest(value)) { value; }
}
type Test = { test: string }
function isTest(val: unknown): val is Test { return true }
value is not narrowed to Test, it's narrowed to T & Test. The generic type argument is kept.
Activity
MartinJohns commentedon May 7, 2021
Duplicate of #28131.
43081j commentedon May 7, 2021
The second part of this is. There are two issues i would say, the generic function can be re-ordered to have the same order and will still error.
e.g.
MartinJohns commentedon May 7, 2021
Otherwise you can pass in this object:
{ hasOwnProperty: () => "example" }.43081j commentedon May 7, 2021
Tdoesn't extendobject...MartinJohns commentedon May 7, 2021
See my update. If you don't make
TextendsObjectyou can pass in an object like{ hasOwnProperty: () => "example" }.And
'foo' and123both extendObject.43081j commentedon May 7, 2021
out of interest, why isn't that behaviour the same without generics?
unknowncould also be{ hasOwnProperty: () => "example" }could it not?so why is it any different just because we have a
Trather thanunknown? which is just as lacking in typei suppose because
Tmeans the compiler could have inferred the type from higher up the chain and would knowhasOwnPropertyis something different here, whereas withunknownit really has no clue so is a bit dumber about it. so only because the compiler knows more in the case of generics it disallows thisMartinJohns commentedon May 7, 2021
I don't know about the specifics, you'd need to wait for the TypeScript team or someone else more knowledgable.
But your guess sounds like a good one to me. It's similar to this example:
valueis not narrowed toTest, it's narrowed toT & Test. The generic type argument is kept.RyanCavanaugh commentedon May 11, 2021
There are some weird corner cases here I don't recall that lead to this. It's certainly not desirable.