Q215: TypeScript Frontend Architecture Capstone
What Interviewers Want To Evaluate
This capstone checks whether you can connect TypeScript features to real frontend architecture.
Interviewers want strict configuration, domain modeling, React props, forms, API contracts, runtime validation, error modeling, shared utilities, migration planning, build performance, and team governance.
Short Interview Answer
For a large frontend codebase, I would use strict TypeScript, narrow public component APIs, discriminated unions for UI and async states, runtime validation at external boundaries, generated or schema-backed API contracts, and typed error models for expected failures. I would keep advanced type utilities centralized, document the patterns, track suppressions, and make typechecking part of CI so TypeScript improves reliability without becoming type cleverness.
Detailed Interview Answer
TypeScript architecture is not about using every feature.
It is about choosing a consistent safety model.
A senior frontend TypeScript system needs:
strict compiler settings
clear domain models
safe React component APIs
typed forms and validation
trusted API boundaries
typed expected errors
readable shared utilities
fast feedback loops
team conventions
migration discipline
Compiler Baseline
Start with strict mode.
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noUncheckedIndexedAccess": true
}
}
Not every project can enable every flag on day one.
But the target should be visible.
For legacy code:
measure existing errors
protect new code
clean shared types first
migrate feature slices
replace any with unknown at boundaries
track suppressions
Domain Modeling
Domain types should represent valid states.
Avoid loose models like:
type RequestState<T> = {
loading: boolean;
data?: T;
error?: string;
};
Prefer:
type RequestState<T> =
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; message: string };
This blocks impossible combinations.
Component API Rules
Component APIs should be easy to call correctly.
Rules I would standardize:
children must be intentional
variants should use unions, not many booleans
callbacks should expose domain values when possible
accessibility props must be required when visual labels are absent
generic components must preserve real caller data
Example:
type Action =
| { kind: "link"; href: string; label: string }
| { kind: "button"; onClick: () => void; label: string };
This is better than a component accepting every possible prop at once.
Form Architecture
Forms should separate:
raw input values
parsed domain values
field errors
form-level errors
submit state
server response
Use runtime validation.
TypeScript helps after validation.
It does not replace validation.
For serious forms, schema-backed validation is usually worth it.
API Boundary
The network is untyped.
I would design an API layer that:
treats raw JSON as unknown
validates important responses
normalizes transport shape into UI models
models error responses
handles version changes explicitly
keeps components away from backend quirks
Example flow:
fetch raw JSON
validate response
normalize to view model
return typed result
render from stable UI state
Error Strategy
Expected failures should be typed.
type AppError =
| { kind: "validation"; fields: Record<string, string> }
| { kind: "auth"; redirectTo: "/login" }
| { kind: "network"; retryable: true; message: string };
Unexpected failures should be thrown, logged, and handled by boundaries.
This separation keeps UI states predictable.
Shared Type Utilities
Advanced utilities should live in shared locations.
Examples:
Result
AsyncState
FieldErrors
Brand
ApiResult
EventPayloadMap
Do not scatter complex conditional types through features.
Feature teams should mostly consume readable helpers.
Type Performance
TypeScript can slow down if types become too complex.
Watch for:
huge generated unions
deep recursive conditional types
excessive module augmentation
heavy schema inference everywhere
large barrel files
slow editor feedback
The developer experience matters.
If typechecking is too slow, teams will avoid it.
Governance
Team conventions should be written down.
Examples:
no new implicit any
unknown at external boundaries
prefer unions for async state
runtime validation for important APIs
no broad declare module patterns
use @ts-expect-error with explanation
remove stale suppressions
Good TypeScript architecture is social as well as technical.
Migration Plan
For a large codebase:
1. inventory compiler settings and any usage
2. protect new code with stricter rules
3. fix generated API/client types
4. migrate shared UI components
5. migrate forms and async state
6. add validation to risky boundaries
7. track and remove suppressions
8. measure build and editor performance
This avoids freezing delivery.
Common Mistakes
Common mistakes include:
using TypeScript only as autocomplete
casting external data without validation
turning every component into a generic abstraction
allowing any in shared helpers
using type tricks that only one person understands
forgetting accessibility in component APIs
ignoring typecheck performance
TypeScript should make the product safer and the team faster.
Senior Trade-Offs
I would be strict at boundaries and pragmatic inside implementation.
Strict:
API contracts
forms
permissions
auth
shared components
domain state
error models
Pragmatic:
local inference
temporary migration suppressions
small internal helpers
experiments behind cleanup tickets
This balances reliability and delivery.
Interview Framing
In an interview, say:
My TypeScript architecture goal is to prevent invalid states at compile time and validate untrusted runtime data at boundaries. I keep the advanced type machinery centralized and readable so the whole team benefits from it.
Revision Notes
- Strict compiler settings are the foundation.
- TypeScript does not validate runtime data.
- React props are public component APIs.
- Forms and APIs need runtime validation.
- Expected errors should be modeled.
- Advanced utilities should be centralized and readable.
- Typecheck performance is part of architecture.
Follow-Up Questions
- How would you migrate a large app to strict TypeScript?
- What should be validated at runtime?
- How do you keep component APIs safe?
- When do advanced type utilities become harmful?
- How would you govern
anyand suppressions?
How I Would Answer This In A Real Interview
I would describe TypeScript as an architecture tool for making invalid states harder to express. I would enable strict checks, model async and UI states with unions, keep React props precise, validate APIs and forms at runtime, and use typed result/error models for expected failures. I would centralize complex type helpers and document conventions so the safety model is shared by the team, not hidden in clever code.