TypeScript Troubleshooting Guide
Issue 1: "Property does not exist on type"
Symptom: error TS2339: Property 'foo' does not exist on type 'Bar'. on code that "should" work.
Root Cause: The value's inferred or declared type genuinely doesn't include that property — either a typo in the property name, the type definition is out of date relative to the actual data, or the value's type is broader than expected (e.g. a union where only some members have that property).
Debug steps:
Fix patterns:
if (r.status === "ok")) before accessing the propertyIssue 2: "Object is possibly 'undefined'" / "possibly 'null'"
Symptom: error TS2532: Object is possibly 'undefined'. on an access that "always works" in practice.
Root Cause: strictNullChecks (part of strict) correctly flags that the type allows undefined/null, even if a specific runtime path never actually produces it — the compiler reasons from the type, not from your knowledge of the data.
Debug steps:
Fix patterns:
Fix 3 is a real escape hatch, not a solution — it removes the check without adding any actual safety, and a wrong assumption there fails at runtime exactly like plain JavaScript would have.
Issue 3: A third-party library has no types (or the types don't match reality)
Symptom: Could not find a declaration file for module 'some-lib'. or the library's types compile fine but don't match what the library actually returns at runtime.
Root Cause: Either no types were ever published for the package, or a published @types package has drifted out of sync with the library's actual current behavior (a real, if less common, occurrence with community-maintained types).
Debug steps:
Fix patterns:
Issue 4: `any` creeping into a codebase silently
Symptom: Type safety "feels" weaker over time even though most files are .ts; autocomplete stops working in places it used to.
Root Cause: any is contagious — once a value is any (an unchecked third-party return, a quick fix under deadline pressure, a forgotten // @ts-ignore), everything that consumes it downstream silently becomes untyped too, with no compiler warning that this happened.
Debug steps:
Fix patterns:
noImplicitAny (part of strict) so an implicit any (a forgotten annotation) is a compile error, not a silent fallbacknoExplicitAny-style lint rules (e.g. @typescript-eslint/no-explicit-any) to flag every deliberate any for review, rather than letting it blend into the codebase invisiblyunknown plus a narrowing check, not any — this preserves the "must check before use" guarantee any throws away entirelyIssue 5: Slow type-checking on a large project
Symptom: tsc takes minutes, or editor autocomplete/hover lags noticeably on a large codebase.
Root Cause: The type checker's cost scales with the complexity of the types themselves (deeply nested conditional/mapped types, very large unions, unnecessarily deep generic constraint chains), plus re-checking .d.ts files in node_modules that don't need re-verification.
Debug steps:
Fix patterns:
tsc only rebuilds what actually changed instead of the whole project every timePrevention Tips
strict: true from a project's first day — retrofitting it onto a large, already-loose codebase later is far more painful than growing with itany as something that needs a one-line comment explaining why, reviewed like any other deliberate exception, not a default reflexunknown over any at any genuinely untyped boundary (API responses, third-party libraries, catch blocks)@types packages' versions reasonably in sync with the library versions they describe — a large version gap is a common, avoidable source of type/reality mismatchestsc --noEmit in CI, not just rely on individual developers' editors catching errors before commit
