TypeScript Version: 2.3.4
Code
type Foo = {
foo:string;
};
function isFoo(arg?:any):arg is Foo|undefined{
return true;
}
function logic(arg?:object){
if (isFoo(arg)){
arg.foo; //Error:(..., 13) TS2532:Object is possibly 'undefined'.
arg!.foo; //Error:(..., 18) TS2339:Property 'foo' does not exist on type 'object'.
}
}
Expected behavior:
arg! should resolve to foo if it's already inferred that arg is Foo|undefined
Actual behavior:
arg! is resolved to object
How about a double bang?
argggg!!!!!!.foo;
Why would you create a custom type guard that included undefined? That doesn't sound very realistic.
It isn't a realistic example, but it's a clear and simple reproduction of inference information that gets lost by using the bang operator. The real-life scenario is a lot messier.
consider this example then:
function isFoo(arg?:any):arg is Foo{
return true;
}
function logic(arg?:object, b?:boolean){
if (isFoo(arg)){
arg = b? undefined : arg;
if (!b) {
arg.foo; //Error:(..., 13) TS2532:Object is possibly 'undefined'.
arg!.foo; //Error:(..., 18) TS2339:Property 'foo' does not exist on type 'object'.
}
}
}
I think there are some problems with how object gets narrowed in general. For example:
interface Foo {
foo;
}
declare function isFooMaybe(x: any): x is Foo | undefined;
declare var a: object | undefined;
if (isFooMaybe(a)) {
var b = a // (object & undefined) | (object & Foo)
}
Most helpful comment
How about a double bang?