JSON to TypeScript: Differences, Edge Cases & Pitfalls

Generate TypeScript interfaces from JSON with optionality inference and markers for unions and nested arrays.

Interface accuracy depends entirely on how representative the sample is: a field is required only if it appears in every object, empty arrays give no element type, and literal unions and optionality need manual tuning. It removes typing labour, not type design.

Format Differences

AspectJSONTypeScript types
TypingNone; values exist at runtime onlyCompile-time checks with IDE hints
OptionalityA field may be missingExplicit with ? or | undefined
Literal unionsNo such concept"a" | "b" narrows the allowed values
Numbers and stringsJust number/stringNarrowable to literals and template literal types
NamingNo type namesHumans supply semantic names; tools emit Root/Item
Discriminated unionsHeterogeneous objects in one arrayModel with a discriminant property
Runtime validationNoneTypes are erased at compile time, so validate at runtime too
Code sizeThe dataType declarations emit no runtime code

Edge Cases

  • A field is required only if present in every sample; one missing sample flips it to optional and loosens the contract.
  • JSON null must be written as | null explicitly, or strict mode rejects the assignment.
  • Dates are plain strings and the type system cannot tell them from any other string; apply a template literal type.
  • Integers beyond 2^53 lose precision in JS, so typing them as number hides the bug — use string for that field.

Common Pitfalls

  • Committing the generated types as the contract; the loose optionality lets nulls reach production.
  • Interfaces all named Root/Item, so six months later nobody knows which type maps to which endpoint.
  • Large ID numbers typed as number are damaged on parse while type checking stays silent.
  • Relying on types for runtime validation — they vanish after compilation and invalid data still arrives.

Related Tools