How Do Typed Interfaces Help Catch Data Errors?
From the earlier reference collection. Read the current software blog.
Types catch many mistakes at boundaries between program components, but they cannot establish that incoming data is truthful or valid. Pair typed interfaces with runtime checks.
Types make expectations explicit
A typed interface describes what one part of a program expects from another. A function might accept a temperature as a decimal number and return a formatted string. A compiler or static checker can flag a call that passes a text label where a number is required, or a caller that treats the returned string as a numeric value.
This catches mismatches early, often before the program runs. Types can also express choices: a result may be either a successful reading or an error, so callers must account for both cases. Such declarations help maintainers see how data is supposed to move through the system.
A type does not prove the value is sound
The guarantee applies only within the type system’s reach. A decimal number can still be an implausible temperature; a string can be empty; an integer can be outside the supported range. A type declaration that says “timestamp” does not establish that the timestamp came from the correct clock or uses the intended time zone.
Consider a JSON response with a field named temperature containing 9999. A client may parse it successfully as a number, and its typed model may accept it. The application still needs a domain rule to decide whether that value is plausible for its use.
Validate at untrusted boundaries
Treat data from a network, file, user, or external process as unknown until it has been checked. Validate required fields, their runtime types, allowed ranges, and relationships. For a reading, a parser might require a numeric value, a recognized unit, and a timestamp in an accepted format. It can then convert the result into an internal type whose constructor only permits validated values.
This separates two jobs: runtime validation establishes that external data meets the application’s rules, while static types help preserve those rules as data passes through the program. Keep errors specific enough to identify the field or condition that failed, without assuming malformed input is trustworthy.
Use both layers deliberately
Typed interfaces are especially useful between modules because they make accidental misuse easier to detect and review. Runtime validation matters at boundaries because data can be incomplete, stale, corrupted, or produced by a version the program does not recognize.
A practical workflow is to parse external input into a permissive raw representation, validate it, and only then create the stricter internal representation. Add tests for both a valid example and boundary failures such as a missing field or an out-of-range value. Types reduce classes of mistakes; validation handles facts that only the running program can inspect.