Data and state modeling: object types, interfaces, unions, and safer API shapes
Move from loose JavaScript objects toward explicit TypeScript models for handlers, payloads, and API results.
by the end of this lesson you can
- →Models result states deliberately instead of as one loose object
- →Uses object types or unions to improve the caller contract
- →Avoids hiding invalid state combinations behind optional fields
Overview
JavaScript and Node code often evolves around flexible object literals and conventions that teams learn over time. TypeScript is most valuable when it turns those conventions into explicit shapes, especially at API boundaries and in stateful application flows.
In JavaScript/Node, you often
pass around objects whose expected fields are known socially or by tests more than by the function signature itself.
In TypeScript, the common pattern is
to define object types, interfaces, and unions that make legal payloads and states obvious to both the compiler and the next maintainer.
why this difference matters
This lesson is the heart of the JS/Node-to-TypeScript transition. Better object modeling is where teams feel safer refactors and fewer accidental interface breaks.
JavaScript/Node
function handleRequest(req) {
return { id: req.params.id, ok: true };
}TypeScript
type RequestParams = { id: string };
type HandlerResult = {
id: string;
ok: true;
};
function handleRequest(req: { params: RequestParams }): HandlerResult {
return { id: req.params.id, ok: true };
}Deeper comparison
JavaScript/Node version
const event = { type: "user.created", id: "1" };TypeScript version
type Event =
| { type: "user.created"; id: string }
| { type: "user.deleted"; id: string };Reflect
Why is an explicit union or object type often a better fit than a broad shape-ish object in a growing Node codebase?
what a strong answer notices
A strong answer mentions safer public contracts, fewer accidental optional-field assumptions, and clearer signaling about which object variants are actually legal.
Rewrite
Rewrite this JavaScript API result shape into TypeScript so callers can tell what is guaranteed versus optional.
Rewrite this JavaScript/Node
return { ok: true, user, error: null };what good looks like
- Models result states deliberately instead of as one loose object
- Uses object types or unions to improve the caller contract
- Avoids hiding invalid state combinations behind optional fields
Practice
Design TypeScript types for an event emitter payload contract with three event names and distinct payload shapes.
success criteria
- Defines payload shapes precisely
- Shows where unions or mapped object types improve safety
- Keeps the resulting API recognizable to a JavaScript/Node team
Common mistakes
- Keeping one giant object type with too many optional fields because it feels close to the original JavaScript.
- Using Record<string, unknown> where the code really knows much more.
- Treating interfaces as documentation only instead of as public contract definitions.
takeaways
- ●This lesson is the heart of the JS/Node-to-TypeScript transition. Better object modeling is where teams feel safer refactors and fewer accidental interface breaks.
- ●A strong answer mentions safer public contracts, fewer accidental optional-field assumptions, and clearer signaling about which object variants are actually legal.
- ●Defines payload shapes precisely