This is the overlooked advantage of a schema (e.g. in GraphQL): it forces you to think about the data types and contract, and serves as a good way to align people working on different parts of the code. It also scales to other languages besides TypeScript which helps if you ever want to migrate your backend to something else or have clients in other languages (e.g. native mobile apps in Swift, Kotlin, etc).
TypeScript is actually a great schema language and fixes a number of problems in GraphQL's SDL, especially the lack of generics.
I think if you're defining a JSON API, that TypeScript is a natural fit since its types line up with with JSON - ie, number is the same in both and if you want something special like an integer with more precision, then you have to model it the same way in your JSON as your TypeScript interfaces (ie, a string or array). This makes TS good even for backends and frontends in other languages. You can also convert TS interfaces to JSON Schema for more interoperability.
It’s not a perfect mapping with JSON. Everyone knows that stuff like functions and dates can’t go over JSON, but there are also subtler things, like the fact that undefined can’t exist as a value in JSON. I’ve seen codebases get pretty mixed up about the semantics of things like properties being optional versus T | undefined.
> Everyone knows that stuff like functions and dates can’t go over JSON, but there are also subtler things, like the fact that undefined can’t exist as a value in JSON
I use `null` for that purpose, and it's been pretty reliable. What are the situations where that falls down?
I also like null | T for required properties, but for whatever reason I have seen that undefined | T is a much more common convention in the TypeScript world. Maybe the reason for that is the semantic about how object access returns undefined, but that’s precisely the source of ambiguity between “object has property X with value undefined” and “object does not have property X”.
TS is a pain with JSON Schema or OpenAPI because it doesn't directly support things like integer or precision. TS does not easily support things like `"exclusiveMinimum": 5`, `"type": "integer"` or patterned (regex) fields.
So if you want to convert your TS interfaces to JSON Schema, you may need to provide additional constraints via JSDoc and use a generator that understands those annotations. But your TS interfaces cannot express those constraints directly.
There are a number other related complications surrounding these more expressive schema definitions - like building types from them and interacting with them at runtime.
Sure, if you have TS in your backend. There are OpenAPI to zod generators that can help get you started, even if they don’t give you perfect zod schemas out the gate.
Jesus, if you're making a JSON API just use JSONSchema, which while not perfect, is quite nice for language interop (and more powerful than typescript)
I'll "just" use the type system built into my programming language until the pain of supporting multiple languages is more expensive than installing JSONSchema tooling and messing with code generation.