I am a big fan of TypeScript’s interfaces
for this job. They’re especially well-suited for data that springs into existence outside the scope of the app (i.e. that comes from external sources like HTTP backends), because they are duck-typed and contain no problematic quasi-intelligent logic.
Most of this can be handled by either optional properties or union types.