On this page
The core idea
TypeScript checks your code at compile time and then erases the types. When you write const course = await response.json() as Course, the compiler believes you, but nothing checks that the server actually returned a Course. If a field is missing or has the wrong type, the error appears far away, in code that assumed the data was valid. The fix is to validate data where it enters your program and produce a typed value only after the check passes. A schema library or a hand-written type guard both work; the important part is the boundary.
A practical approach
Step 1
List every place untrusted data enters: HTTP responses, request bodies, query parameters, local storage, environment variables, files and messages from other services.
Step 2
At each boundary, parse the data with a validator that returns either a typed value or a clear error. Schema libraries can generate the TypeScript type from the schema so the two never drift apart.
Step 3
Decide what happens on failure: reject a request with a 400, show a form error, or stop the application at startup when required configuration is missing.
Step 4
Keep validated data typed all the way through. Inner functions accept the validated type and never re-check it.
Step 5
Remove as casts on external data during code review; each one marks a boundary without validation.
Worked example
A dashboard reads PORT and DATABASE_URL from environment variables typed as string. In production DATABASE_URL is missing, and the app starts normally, then fails on the first request with a confusing connection error. Validating the environment at startup, with a schema that requires a URL and coerces PORT to a number, makes the deployment fail immediately with 'DATABASE_URL is required'. The rest of the code receives a typed config object it can rely on.
A mistake to avoid
Do not validate the same data repeatedly in every function. That spreads checks across the codebase and makes it unclear which code is responsible. Validate once at the boundary and pass the trusted, typed result inward.
Try it yourself
Find one fetch call or request handler in your project that uses an as cast. Write a validator for the data, return a helpful error when validation fails and add a test with a malformed payload.
Your implementation checklist
- Every external input has a validation boundary
- Validated values carry precise TypeScript types
- Validation failures produce a clear, actionable error
- Configuration is validated when the app starts
- No as casts are used on unvalidated external data
Share or cite this guide
Innovate with Ajay Editorial (2026-10-07). Validate External Data at Runtime; TypeScript Types Alone Will Not. https://innovatewithajay.com/blogs/validate-external-data-in-typescript
