Description
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 parentisAmbientModule
check.
⏯ Playground Link
💻 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.