In the 4.9 announcements, they have described better narrowing with 'in' now. So, I took their example to the playground and tinkered with it. I found that impossible conditions with typeof
and in
were being narrowed to never
, instead of generating a warning or error:
// Should be illegal but doesn't error out...?
if (typeof packageJSON.name === "string" && typeof packageJSON.name === "number") {
I thought that TypeScript would be able to deduce that packageJSON.name
was a string, which means that checking if the type of packageJSON.name
is a number on the right should be impossible. To my dismay, I also found that checking literals doesn't get TypeScript to gripe:
typeof 123 === "string" // OK, but is obviously impossible?
This behavior is also exhibited with in
:
// How can it both have and not have the "name" key?
if (packageJSON && typeof packageJSON === "object" && "name" in packageJSON && !("name" in packageJSON)) {
To clarify, the types are correctly narrowed to never
, but my expectations were that TypeScript should be able to warn me about using an impossible condition. TypeScript already does this for equality checks:
// TS knows that packageJSON is 0, so the RHS is impossible
if (packageJSON === 0 && packageJSON === 1) {
I don't know why this is happening. Is it by design or a limitation? What can I do to prevent or warn about this (maybe a linter)? Here's a playground with the examples above.
CodePudding user response:
TypeScript is able to narrow types in cases where the type can be determined to be impossible based on the conditions. In the first example, since TypeScript knows that packageJSON.name is a string, it can deduce that the condition on the right is impossible and narrow the type to never. In the second example, TypeScript knows that the literal 123 is a number, so it can deduce that the condition on the right is impossible and narrow the type to never. In the third example, TypeScript knows that packageJSON is an object and that the "name" key exists on packageJSON, so it can deduce that the condition on the right is impossible and narrow the type to never.
This behavior is by design, as TypeScript is able to narrow down types in certain cases. However, if you want to prevent this behavior, you can use a linter like TSLint.