Skip to content

bang operator resets type inference #16945

Closed

Description

@amir-arad

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

Activity

  1. DeDuckProject commented on Jul 5, 2017

    @DeDuckProject

    How about a double bang?

    argggg!!!!!!.foo;
    
  2. changed the title [-]band operator resets type inference[/-] [+]bang operator resets type inference[/+] on Jul 5, 2017
  3. kitsonk commented on Jul 5, 2017

    @kitsonk
    Contributor

    Why would you create a custom type guard that included undefined? That doesn't sound very realistic.

  4. amir-arad commented on Jul 5, 2017

    @amir-arad
    Author

    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'.
            }
        }
    }
  5. DanielRosenwasser commented on Jul 6, 2017

    @DanielRosenwasser
    Member

    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)
    }
  6. 9 remaining items

  7. RyanCavanaugh commented on Oct 28, 2025

    @RyanCavanaugh
    Member

    This works now

  8. locked as resolved and limited conversation to collaborators on Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: check: Control FlowThe issue relates to control flow analysis

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions