TypeScript — TS2339: Property does not exist on type
Fix TS2339 by narrowing unions, extending interfaces, or correcting the type instead of asserting.
Symptoms
- error TS2339: Property 'name' does not exist on type 'A | B'
- The property exists at runtime but the compiler complains
- Accessing a field fails after destructuring
- A DOM element lacks element-specific properties
Possible causes
- The value is a union and the property exists only on one member
- The interface genuinely lacks the property
- An index signature is missing for dynamic keys
- A generic type parameter is unconstrained
Diagnosis steps
Read the reported type
npx tsc --noEmitInterpretation
The message shows the exact type lacking the property, which tells you whether it is a union, a generic or a plain interface.
Narrow before access
if ("name" in value) { value.name }Interpretation
The in operator narrows a union so the property becomes accessible on the narrowed branch.
Check the type definition
grep -n "interface \|type " src/models.tsInterpretation
If the property is genuinely part of the data, the type definition is wrong and should be corrected.
Root cause
The compiler sees a type that does not declare the accessed property, either because the property belongs to only some members of a union or because the type definition is incomplete.
Fix
Narrow unions with type guards or discriminated fields, add the property to the interface when it is genuinely present, or provide an index signature for dynamic keys.
Verify the fix
Rerun the type checker and confirm the error is resolved, and run tests to confirm the accessed property exists at runtime on all paths.
Symptom walkthrough
The compiler reports TS2339, claiming a property does not exist on a type even though the value has it at runtime. This usually means the value is a union where only some members declare the property, or a generic without a constraint, or an interface that omits a field the data actually carries. Asserting with as any hides the discrepancy rather than resolving it.
Fix in practice
Narrow the value before access using the in operator, a discriminated union or a type guard, so the compiler knows the property is present. If the data really contains the field, add it to the interface. For dynamic keys, add an index signature rather than casting.
Verification
Rerun the type checker and confirm the error is gone, then run the tests and confirm the property is present on the exercised paths. Types plus runtime both passing proves the fix.
Diagnostic commands
Check the behavior with commands like these:
npx tsc --noEmit
if ("name" in value) { value.name }
grep -n "interface \|type " src/models.ts