The following example confuse me:
class MyClass
{
public MyProp = "";
}
var object: any = null;
if (object instanceof MyClass)
console.log(object.MyProp, object.NonExistant); // <-- No error, no intellisense
Why isn't the type guard giving me the correct type within the checked context?
User-defined type guards and instanceof
type guards does not narrow types that are any
(including union and intersection types with any
) .
The only thing that will narrow an any
in a type guard is using the typeof
check and checking for the primitive string
, bool
, and number
:
var something: any;
if (typeof something === "string")
{
something.NonExistant(); // <- Error, does not exist on `string`
something.substr(0, 10); // <- Ok
}
The other generic typeof values, function
, object
and undefined
, does not narrow any
if one would try to use them like the above example.
There is also an open issue for making it possible to narrow any
to primitives within user-defined type guards, milestoned at TS 2.0.
This is a conscious design decision and not a bug
The primary motivation seems to have been that type-guarding a type is generally narrowing the possible type and we get access to more properties that we can be sure exists within the checked context. But in the case with type-guarding the special any
, we already have access to all members that could possibly exists, so doing type-guarding on an any
as like you expected in your example would actually limit us.
Another motivation also seems to be that there is too much crappy code out there that would break if TypeScript narrowed any
's just like the other types.
Workaround
If you have a variable that can be an instance of an arbitrary class, use the type Object
or unknown
instead of any
and type guarding will work as expected.