← Debugging Guides

阅读中文版本

TypeScript TS18046 — Error Is of Type unknown

Fix TS18046 by narrowing unknown values with type guards, using instanceof Error, and opting into useUnknownInCatchVariables deliberately.

intermediatedebuggingtypescriptstrictunknown

Symptoms

  • error TS18046: 'e' is of type 'unknown'
  • The error appeared after enabling strict mode
  • Accessing e.message in a catch block fails to compile

Possible causes

  • Strict mode or useUnknownInCatchVariables makes catch bindings unknown
  • An index access returns unknown under noUncheckedIndexedAccess
  • JSON.parse or a generic API returns unknown and is used without narrowing

Diagnosis steps

Reproduce the compile error

npx tsc --noEmit 2>&1 | grep TS18046

Interpretation

The message names the variable and the operation, showing where narrowing is needed.

Narrow with a guard

if (e instanceof Error) console.log(e.message);

Interpretation

instanceof Error narrows unknown to Error so message and stack are accessible.

Root cause

With useUnknownInCatchVariables (implied by strict), catch clauses bind unknown because anything can be thrown. TypeScript forbids member access on unknown until a guard proves a narrower type.

Fix

Narrow before use: instanceof Error for error-like values, a custom isApiError guard for shapes, and a helper that converts unknown to a message safely.

Risk note

Casting with `as Error` skips the check and reintroduces the runtime bug the strict setting prevents.

Verify the fix

Run tsc --noEmit and confirm TS18046 is gone; add a test throwing a string and an Error and assert both produce a readable message.

Symptoms

When you hit “TypeScript TS18046 — Error Is of Type unknown”, guessing wastes time. The guide below follows evidence: reproduce the symptom, run targeted diagnostics, identify the root cause, apply the fix, and verify it with concrete checks.

Observed symptoms include:

  • error TS18046: ‘e’ is of type ‘unknown’
  • The error appeared after enabling strict mode
  • Accessing e.message in a catch block fails to compile

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Reproduce the compile error

npx tsc --noEmit 2>&1 | grep TS18046

The message names the variable and the operation, showing where narrowing is needed.

Step 2: Narrow with a guard

if (e instanceof Error) console.log(e.message);

instanceof Error narrows unknown to Error so message and stack are accessible.

Likely contributors, in order of frequency:

  • Strict mode or useUnknownInCatchVariables makes catch bindings unknown
  • An index access returns unknown under noUncheckedIndexedAccess
  • JSON.parse or a generic API returns unknown and is used without narrowing

Root Cause

With useUnknownInCatchVariables (implied by strict), catch clauses bind unknown because anything can be thrown. TypeScript forbids member access on unknown until a guard proves a narrower type.

The Fix

Narrow before use: instanceof Error for error-like values, a custom isApiError guard for shapes, and a helper that converts unknown to a message safely.

Watch out: Casting with as Error skips the check and reintroduces the runtime bug the strict setting prevents.

function messageOf(e: unknown): string {
  if (e instanceof Error) return e.message;
  if (typeof e === 'string') return e;
  try { return JSON.stringify(e); } catch { return String(e); }
}

try { risky(); } catch (e: unknown) {
  console.error(messageOf(e));
}

Verify and Prevent

Run tsc –noEmit and confirm TS18046 is gone; add a test throwing a string and an Error and assert both produce a readable message.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.