TypeScript Version: 2.2.1, 2.3.2
--strictNullChecks
Code
class Foo {};
let foo: Foo;
if (foo instanceof Foo) { // Throws TS2454 variable foo is used before being assigned
// foo is Foo
}
class Bar {};
let bar: Bar | undefined;
if (bar instanceof Bar) {
// bar is Bar
}
Expected behavior:
Unassigned left hand variables in a instanceof check should not throw TS2454.
instanceof can return false when left hand unassigned variables, or null, or undefined
Actual behavior:
Throws TS2454 variable foo is used before being assigned
Inconsistent behavior when variable type is a union with undefined
Why write a condition which is always false? That doesn't make any sense
You make a good point. However, the use-case I discovered it in was using a try-catch-finally.
The variable declared outside of the try-catch-finally may have been assigned anytime inside the try, catch, or finally blocks thus instanceof has a possibility of returning true.
example:
class Foo {
doSomethingThatMayThrow() {
throw new Error('whoops');
}
cleanup() {
// perform some kind of cleanup
}
};
let foo: Foo;
try {
foo = new Foo();
foo.doSomethingThatMayThrow();
} finally {
if (foo instanceof Foo) { // Throws TS2454 variable foo is used before being assigned
// foo is still Foo
foo.cleanup();
}
}
I have this block of code that throws the same error. Is this related to this bug or am I doing something wrong? I have "alwaysStrict": true and "strictNullChecks": true set.
async function foo() {
let bar: IBar
try {
bar = await Bar
.query()
....
} catch (err) {
ctx.throw('Some error')
// throw new Error() // <- if I uncomment this line the error goes away
}
ctx.body = bar // <- Throws variable 'bar' is used before being assigned. (TS2454)
If I remove "strictNullChecks": true from ts.config, then the error goes away.
@demisx the error is correct; it's possible bar doesn't get assigned
@RyanCavanaugh Thanks. I see. I've updated the example above with a little more detail inside the catch {...}. Please note, that if I uncomment throw new Error() in the catch block, TS understands that this block will never exit and the error goes away.
What would be the right way to help TS compiler understand that ctx.throw() also never exits? This is the method's signature, but TS still doesn't see it as never exiting:
throw(...properties: Array<number | string | {}>): never;
return ctx.throw('some error')
@RyanCavanaugh That's what I did. 馃憤
if foo is not assigned at declaration site, consider declaring it using the ! modifier:
let foo!: Foo;
try {
foo = new Foo();
foo.doSomethingThatMayThrow();
} finally {
if (foo instanceof Foo) {
// foo is still Foo
foo.cleanup();
}
}
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Most helpful comment
if
foois not assigned at declaration site, consider declaring it using the!modifier: