Skip to content

Recursive types — a type for any JSON value

Level: 301 · for anyone who has typed data read from a file

Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The questions below are what the finished page has to answer.

One line: type Json = … | Json[] | { [key: string]: Json } names itself and covers JSON at any depth, yet a value typed by an interface with the same fields is rejected, because only type aliases get an implicit index signature.

Keywords: recursive type, implicit index signature

What the finished page will answer

  • How can type Json mention itself, and how deep a value does it accept?
  • Why is a value typed by interface User rejected as Json when the same fields under type User are accepted?
  • Why are new Date() and { a: undefined } rejected, when JSON.stringify handles both?
  • Which values does Json accept that JSON cannot hold — what does JSON.stringify(NaN) produce?
  • When does tsc give up on a recursive type with TS2589, 'Type instantiation is excessively deep and possibly infinite'?

Examples it will need

  • recursive_types_json_tserror.ts — the errors for an interface value, a Date and an undefined field assigned to Json
  • recursive_types_nan_ts.ts — JSON.stringify of values the Json type accepts, including NaN and Infinity, which come out as null
  • recursive_types_depth_tserror.ts — the TS2589 error from a recursive type that counts too deep

See also

Sources to start from