I've googled for the last hour and I haven't found a good answer or explanation for my problem.
I have a member variable defined as a union type, of a primitive(number) or an interface (KnockoutObservable), and I can not use the instanceof or typeof typeguards without generating an error. I am using VS2013 update 4 with Typescript 1.4. I have set up a few examples to demonstrate the issue:
class foo {
foo() {}
}
class bar {
bar() {}
}
interface baz {
baz();
}
// This case breaks
var var1: number|foo;
if (typeof var1 === "number") {
var1 = 5;
}
// Generates error "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter."
else if (var1 instanceof foo) {
var1.foo();
}
// This also breaks, same error as above
if (var1 instanceof number) {
var1 = 5;
}
else if (var1 instanceof foo) {
var1.foo();
}
// This case works
var var2: foo|bar;
if (var2 instanceof foo) {
var2.foo();
}
else if (var2 instanceof bar) {
var2.bar();
}
// This case breaks as well
var var3: foo|baz;
if (var3 instanceof foo) {
var3.foo();
}
// Generates error: "Cannot find name 'baz'."
else if (var3 instanceof baz) {
var3.baz();
}
My question is why do cases 1 and 3 break? We are creating KnockoutJS components, where the parameter could be an observable or a primitive. Since KnockoutObservable is an interface, this pretty much shuts down being able to use union types in our pattern; if we want the parameter to be either we have to revert to using 'any'.
Some of the things I have found about this (such as here) seem to imply this is fixed in 1.5. Can anybody give me the lowdown on this?
Note that assigning to a variable anywhere in a function body "turns off" type guards on that variable, so I've removed assignments from this example.
Basically, there's the case that works as expected, a case that ought to work but doesn't, and a case that doesn't work because there's no runtime type information for interfaces. instanceof
is a JavaScript operator that checks the prototype chain of an object, not a TypeScript construct for doing type operations.
var var1: number|foo;
// OK
if (typeof var1 === "number") { }
// Bug #2775
// https://github.com/Microsoft/TypeScript/issues/2775
if (var1 instanceof foo) { }
if (var1 instanceof number) { }
// OK
var var2: foo|bar;
if (var2 instanceof foo) { }
if (var2 instanceof bar) { }
// TypeScript does not have reflection; there is no
// value 'baz' to 'instanceof' at runtime.
if (var3 instanceof baz) {
var3.baz();
}
The error about x instanceof number
is also intentional; there is no runtime value number
. You might be tempted to write x instanceof Number
; this would be a mistake (42 instanceof Number
is false
, not true
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With