Skip to content

No error for missing method call  #35557

Closed

Description

@mjbvz

TypeScript Version: 3.8.0-dev.20191206

Search Terms:

  • diagnostics
  • conditional
  • missing function call

Code

import * as fs from 'fs';

fs.stat('/path/to/file', function(err, stats) {
    if (stats.isDirectory) { 
        console.log(`[Directory] ${stats.ctime}`)
    }
});

Expected behavior:
Error on isDirectory. This is a method but it has not been called

Actual behavior:
No error reported.

If I remove the console log line

Activity

  1. changed the title [-]No error for missing method call if other property is accessed in conditional body[/-] [+]No error for missing method call [/+] on Dec 6, 2019
  2. MartinJohns commented on Dec 7, 2019

    @MartinJohns
    Contributor

    This will only report an error if strictNullChecks is enabled, and stats.isDirectory is a non-nullable function. See #33178 and #9041.

  3. mjbvz commented on Dec 7, 2019

    @mjbvz
    Author

    This is in strict mode:

    Dec-07-2019 09-36-01

  4. RyanCavanaugh commented on Dec 9, 2019

    @RyanCavanaugh
    Member

    It looks like we're confused by any reference to stats in the body if the if

  5. dragomirtitian commented on Dec 26, 2019

    @dragomirtitian
    Contributor

    The way the check is done for usage seems brittle. The only check that is done is for symbol id equality:

    const functionIsUsedInBody = forEachChild(ifStatement.thenStatement, function check(childNode): boolean | undefined {
        if (isIdentifier(childNode)) {
            const childSymbol = getSymbolAtLocation(childNode);
            if (childSymbol && childSymbol.id === testedFunctionSymbol.id) { // HERE 
                return true;
            }
        }
    
        return forEachChild(childNode, check);
    });

    This has the drawback of not actually working at all for symbols which have not had an id assigned (and we get undefined === undefined). This could be fixed by using getSymbolId which would assign the id, or by direct object equality (since as far as I understand it the same symbol object should be used and id equality when assigned at this location seems no better) but this fix would not fix the following surprising behavior:

    interface StatsBase {
        isDirectory(): boolean;
    }
    function A(stats2: StatsBase, stats: StatsBase) {
        if (stats.isDirectory) { // no error because we access isDirectory on stat2
            stats2.isDirectory(); // comment this and we get an error above
        }
    }

    Playground Link

    The symbols isDirectory is used, in the if condition and in the body but the target is different.

    Proposed solution:

    1. Use getSymbolId for when comparing symbol ids
    2. Compare the expression of the property access to ensure it is the same (if the testedNode is a property access)
  6. locked as resolved and limited conversation to collaborators on Oct 21, 2025
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 TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions