Skip to content

checker.ts :: checkModuleDeclaration(): Redundant type guard erroneously narrows node type to 'never' #45572

Closed
@rafasofizada

Description

@rafasofizada

Bug Report

I have a ready, very easy fix for this bug, so if you indeed recognize this as a bug, please assign it to me, and I'll submit a PR.

🔎 Search Terms

checkModuleDeclaration node type never
checker.ts
isExternalModuleAugmentation
Property 'parent' does not exist on type 'never' (ts2339)

🕗 Version & Regression Information

This is a logical bug in checker.ts that should arise in pretty much any TypeScript version that supports type guards/predicaments. However, since isAmbientModule()'s result is assigned to a variable, and control flow of aliased conditional expressions is introduced only in v4.4.0, this issue will only appear in v4.4.0+ (or any other version with pull request #44730)

Judging by related commits that I've found by using git blame -L37720,37722 src/compiler/checker.ts and
git log -L37720,37722:src/compiler/checker.ts, the bug was introduced somewhere around v2.8-rc:

  • 4a963a2 – Dec 22, 2015, seems to be v1.7.5 or v1.8.0-beta – Added the isExternalModuleAugmentation() check (which will become redundant in the next commit)
  • 5e593ac – Mar 6, 2018, seems to be v2.8-rc – Added a type predicate to isExternalModuleAugmentation(), which created a redundancy with parent isAmbientModule check.

⏯ Playground Link

Close recreation of the issue

💻 Code

checker.ts : line 37664

function checkModuleDeclaration(node: ModuleDeclaration) {
    // ...

    // Control flow analysis of aliased conditional expressions 
    // (e.g. type guard result saved in a variable) are introduced
    // only in v4.4.0 https://github.com/microsoft/TypeScript/pull/44730
    const isAmbientExternalModule = isAmbientModule(node);

   // ...

    if (isAmbientExternalModule) {
        // Before v4.4.0, node here is of type 'TNode'
        // After v4.4.0, node here is of type 'AmbientModuleDeclaration'
        if (isExternalModuleAugmentation(node)) {
            // isExternalModuleAugmentation() contains a redundant isAmbientModule() check
        }
        else if (isGlobalSourceFile(node.parent)) {
        //                          ^^^^^^^^^^^^
        // Here, tsc v4.5.0-dev.20210824 (and all others) give an error:
        // Property 'parent' does not exist on type 'never'.ts(2339)
        // Because of the redundant check in if (isExternalModuleAugmentation(node)) ...,
        // control flows deduces node's type to be 'never'.

        // ...
        } else {
            // ...
        }
    }
    // ...
}

🙁 Actual behavior

Covered in the code examples/playground.

🙂 Expected behavior

Covered in the code examples/playground.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions