# Use types and components to maintain an interface

Canonical page: https://yishto.com/en/learn/web-interface/typescript-and-ui-frameworks/

Author: [Yishto](https://yishto.com/en/about/)

Connect runtime data validation, discriminated states, and component ownership, then distinguish TypeScript checks from React and Vue update and identity mechanisms.

Published: 2026-11-10
Updated: 2026-11-10

A document card starts with a title and later acquires download state, errors, and retry. If every page assembles fields and toggles booleans independently, loading can coexist with an old error or a missing title can enter the success view. Types and components express constraints, while incoming data still needs runtime checks.

The case is a list component receiving validated records, displaying loading, success, or error, and requesting save operations through events. The example checks a synthetic contract without claiming a running framework project.

## Static types do not validate network data

TypeScript checks program relationships before execution; its type annotations are generally erased when JavaScript is emitted. Asserting that a response has a type tells the compiler how to treat it. It does not inspect the JSON at runtime. Null values, outdated fields, and incorrect numbers remain real browser inputs.

Treat external values as unknown at the boundary. Check structure, required fields, types, and allowed ranges before constructing an internal record. A document ID should be a nonempty string with an explicit rule. A date needs a format and timezone convention beyond being a string. Report invalid input rather than conceal it with an empty title.

Compile-time checking and runtime validation can share a contract design, but their evidence differs. Compilation establishes static checks under the current configuration; validation establishes that a particular input satisfies the implemented rules. Neither promises that future server data is always valid.

## Use labeled states for legal combinations

Independent booleans can allow loading, error, and data to be true together, leaving every rendering branch to choose a priority. A state tagged by kind can define allowed fields: loading has no result, success has a list, and error has an error description.

If the product should retain results during a refresh, define refreshing explicitly and specify its retained data. The type should represent required behavior rather than remove useful feedback for coding convenience.

TypeScript can narrow a discriminated union by its tag. Check every handler when adding a state. Distinguish retryable connection errors from invalid-data errors where the product needs different actions.

## Give components explicit inputs and ownership

A card receives its record, saved state, and operation state. It renders them and emits an event or callback requesting a change for a particular ID. The parent owning the list coordinates updating and persistence. Arbitrary mutations of shared global objects obscure where changes originate.

Filtered records, counts, and button text can usually be derived from existing state. Storing a separate count requires synchronization and creates stale-value opportunities. Use effects for external synchronization rather than write every pure calculation back into state.

Split components by responsibility and change patterns. Search input, request results, and an individual card can have useful boundaries. A wrapper without meaningful rules or reuse may add navigation cost. Clear contracts matter more than a prescribed folder count.

## Respect React and Vue state mechanisms

React state read during a render is a snapshot for that render. A setter schedules an update; it does not instantly rewrite the value already read by the current function. Position and keys affect component identity and state preservation. Use stable document IDs so insertion and sorting do not transfer local state to another card.

Vue tracks reactive dependencies and schedules relevant updates. Its reactive usage and component input conventions still matter. Reactivity does not grant every module permission to mutate an object or decide business ownership.

Choose a framework using team experience, ecosystem requirements, existing code, and delivery constraints. Syntax alone does not establish a universal speed winner. Migration changes component and build mechanisms, but does not repair authorization, state contracts, or duplicate data ownership.

## Validate allowed fields offline

The function checks kind-specific fields. Success requires a list, error requires a string, and loading excludes results and errors. An invalid combination has an explicit assertion. The function is neither a TypeScript compiler nor a model of React or Vue scheduling.

```python
def valid(state):
    kind = state.get("kind")
    if kind == "loading":
        return "data" not in state and "error" not in state
    if kind == "success":
        return isinstance(state.get("data"), list) and "error" not in state
    if kind == "error":
        return isinstance(state.get("error"), str) and "data" not in state
    return False
assert valid({"kind": "success", "data": [1]})
assert not valid({"kind": "loading", "data": [1]})
print(valid({"kind": "error", "error": "offline"}))
```

The output is `True`, meaning the synthetic offline error state satisfies these rules. List elements are not validated, and an empty error string would pass. Add those constraints if required. Passing this function does not establish trustworthy document records.

The model separates loading from old data and therefore cannot represent refreshing unchanged. Define its fields and transitions before extending the checks. Broadly relaxing existing branches would discard their useful constraints.

Separate rendering exceptions, request errors, and validation failures. Rendering may need a fallback view; requests need retained input and retry; invalid fields need safe diagnostics and rejection. Catching every case and returning an empty list obscures diagnosis and falsely suggests that no documents exist.

Keep older-response tests when adding fields and define compatibility, rather than update only the type declaration.

## Exercise: verify contracts and components

Define document ID, title, category, and download state, external validation rules, internal state tags, card inputs, and save events. Test five synthetic responses: valid, missing title, incorrect type, empty list, and unknown state. Record acceptance and user feedback for each.

Invalid data must not enter a component as success. Loading, success, and error must not form illegal mixtures. Filtered counts must be derived, and insertion or sorting must preserve state with the intended ID. If using a framework, test its actual update and identity behavior in the project and report the checks run. The offline function establishes only its own contract.

## Sources & further reading

- [TypeScript handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
- [Managing React state](https://react.dev/learn/managing-state)
- [Vue essentials and components](https://vuejs.org/guide/introduction.html)

Sources checked on 2026-11-10. Examples are teaching data, not production measurements.

## Related guides

- [Why the same bytes can be read as different values](https://yishto.com/en/learn/computing/encoding-and-types/)
- [Design offline notes with React Native and Expo](https://yishto.com/en/learn/application-platforms/expo-offline-notebook/)
