Summary
no-unsafe-catch-error-property accepts typeof err === 'object' as a sufficient guard that suppresses all unsafe-property warnings in the catch block:
// no-unsafe-catch-error-property.ts:105-123 (BinaryExpression handler)
// typeof varName === 'object' or 'object' === typeof varName -> top.hasGuard = true
The test suite asserts the null-unchecked form as valid:
// no-unsafe-catch-error-property.test.ts:348 (valid)
`try { f(); } catch (err) { if (typeof err === 'object') { console.log(err.status); } }`
Why this is a false negative
typeof null === 'object'. So when the thrown value is null (or any non-Error object lacking the property), the guard passes and err.status is accessed anyway — null.status throws a TypeError, which is exactly the non-Error-throw failure mode this rule is meant to catch. The guard narrows nothing useful on its own; it gives a false sense of safety and silences the warning on genuinely unsafe code.
Note the very next valid fixture (line 349) does it correctly: typeof err === 'object' && err !== null. The rule should require that companion null check.
Acceptance criteria
- A bare
typeof err === 'object' (with no err !== null / err != null / truthiness companion in the same guard condition) no longer marks the frame as guarded.
typeof err === 'object' && err !== null (and equivalents: err != null, a preceding if (!err) return;, err && typeof err === 'object') continue to be accepted.
err instanceof Error and getErrorMessage(err) guards are unchanged.
- Update
no-unsafe-catch-error-property.test.ts: move the bare-typeof case (line 348) from valid to invalid, keep the null-checked cases (lines 349, 430) valid.
- Apply the same tightening to
no-unsafe-promise-catch-error-property, which shares the identical typeof === 'object' guard logic, for parity.
Relationship to existing issues
Distinct from #42189 (whole-frame vs. flow-sensitive guard placement). This is about the semantic strength of one specific guard form, not where it appears.
Generated by 🤖 ESLint Refiner · 185.1 AIC · ⌖ 12.4 AIC · ⊞ 4.7K · ◷
Summary
no-unsafe-catch-error-propertyacceptstypeof err === 'object'as a sufficient guard that suppresses all unsafe-property warnings in the catch block:The test suite asserts the null-unchecked form as valid:
Why this is a false negative
typeof null === 'object'. So when the thrown value isnull(or any non-Error object lacking the property), the guard passes anderr.statusis accessed anyway —null.statusthrows aTypeError, which is exactly the non-Error-throw failure mode this rule is meant to catch. The guard narrows nothing useful on its own; it gives a false sense of safety and silences the warning on genuinely unsafe code.Note the very next valid fixture (line 349) does it correctly:
typeof err === 'object' && err !== null. The rule should require that companion null check.Acceptance criteria
typeof err === 'object'(with noerr !== null/err != null/ truthiness companion in the same guard condition) no longer marks the frame as guarded.typeof err === 'object' && err !== null(and equivalents:err != null, a precedingif (!err) return;,err && typeof err === 'object') continue to be accepted.err instanceof ErrorandgetErrorMessage(err)guards are unchanged.no-unsafe-catch-error-property.test.ts: move the bare-typeofcase (line 348) fromvalidtoinvalid, keep the null-checked cases (lines 349, 430) valid.no-unsafe-promise-catch-error-property, which shares the identicaltypeof === 'object'guard logic, for parity.Relationship to existing issues
Distinct from #42189 (whole-frame vs. flow-sensitive guard placement). This is about the semantic strength of one specific guard form, not where it appears.