Typescript: bang operator resets type inference

Created on 5 Jul 2017  路  4Comments  路  Source: microsoft/TypeScript

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

Bug

Most helpful comment

How about a double bang?

argggg!!!!!!.foo;

All 4 comments

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)
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

bgrieder picture bgrieder  路  3Comments

Zlatkovsky picture Zlatkovsky  路  3Comments

DanielRosenwasser picture DanielRosenwasser  路  3Comments

blendsdk picture blendsdk  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments