An interface is best when multiple types truly share a stable shape or behaviour and you want to describe that common contract. A union type is better when the function must accept one of several distinct concrete types without pretending they are the same. For audit logging, the union preserves specificity while still enabling one shared implementation.
Interfaces and union types describe different kinds of certainty
For a logging use case, the key distinction is whether you are modelling a shared contract or a set of alternatives. An interface says, “these values all conform to the same structural shape,” which is useful when your logger can rely on the same fields every time. A union type says, “this value will be one of these distinct shapes,” which is better when the log input varies and each variant carries different meaning.
That difference matters because logging often sits at a boundary between business objects and audit output. If you force unrelated event shapes into one interface, you can hide important detail or encourage empty fields that look uniform but are not. If you use a union, the type system keeps the variants honest, which helps preserve the exactness of the event you are recording. In security-oriented logging, that exactness supports better traceability and fewer ambiguous records. For control expectations around logging and auditability, NIST SP 800-53 Rev 5 Security and Privacy Controls is the closest external reference because it frames logging as a control objective rather than a syntax choice. In practice, many teams discover the difference only after a single “generic” interface starts swallowing event-specific fields that they later wish they had preserved.
How the choice affects audit log design
In a logging implementation, an interface is usually the right tool when you have a stable event envelope such as timestamp, actor, action, and source, and every log entry genuinely shares those fields. That works well for common metadata because the logger can depend on a consistent contract. A union type is better when the payload differs by event category, such as login attempts, configuration changes, and permission grants, where each event has some shared metadata but also its own fields that should remain explicit.
The practical question is not whether TypeScript can type the data, but whether the type should communicate sameness or variation. An interface can make a logger easier to consume when all producers are intentionally aligned. A union can make the code safer when producers represent distinct event families and the consumer needs to narrow before using event-specific properties. That narrowing is often valuable in audit logging because it prevents accidental treatment of different security events as if they were interchangeable.
- Use an interface for the invariant wrapper around your log record.
- Use a union for the event-specific payload when the semantics diverge.
- Keep the shared metadata small so variant data does not get flattened away.
- Prefer explicit narrowing in the logger rather than optional fields that blur meaning.
Where this guidance breaks down is when a supposed “common” log shape is actually just a convenience layer over events that no longer share the same semantics.
When a shared log contract stops being the cleaner option
Tighter typing often increases the amount of narrowing or branching needed, so teams must balance readability against precision. If the logging use case is simple and the event families are genuinely aligned, an interface keeps the code easier to understand. If the log entries diverge in fields, intent, or downstream handling, a union usually models the problem more honestly.
There is also a trade-off between convenience and fidelity. An interface with many optional properties may look flexible, but it can conceal the fact that different events are really different shapes. That is often a code smell in audit or security logging, because it reduces the quality of downstream filtering, enrichment, and investigation. By contrast, a union makes the variation visible at compile time, but it can require more deliberate handling wherever the record is consumed.
For this kind of use case, the cleanest design is usually an interface for shared metadata plus a union for the event-specific variants. That combination preserves a stable logging envelope without sacrificing the exactness of the underlying event. If the team later finds that the variants have converged, the union can be simplified; if not, the type system will keep enforcing the distinction. A standard logging shape that survives too many exceptions is usually a signal that the model is hiding more variation than it admits.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
MITRE ATT&CK address the attack and risk surface, while CIS Controls v8 and NIST CSF 2.0 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| CIS Controls v8 | 8 — Audit Log Management | Logging design affects audit trail completeness and consistency. |
| Recommendation — Design log schemas to preserve event detail and support reliable audit review. | ||
| NIST CSF 2.0 | PR.PT-1 — Protective Technology | Type choices shape how logging data is structured and protected for monitoring use. |
| DE.CM-1 — Monitoring for Unauthorised Events | Clear event typing improves the quality of security monitoring signals. | |
| Recommendation — Define logging data structures that keep security events distinguishable for detection and response. Keep event variants explicit so monitoring tools can interpret log records correctly. | ||
| MITRE ATT&CK | T1070 — Indicator Removal on Host | Audit logging exists to preserve evidence against tampering and loss of visibility. |
| Recommendation — Structure logs to retain distinct event evidence that supports investigation and detection. | ||
Practitioner Guidance
What to prioritise: Define the shared audit envelope first, then decide whether the payloads are truly equivalent or only related by context. If the records differ in meaning, keep them as separate variants rather than forcing one “universal” log interface.
What to verify: Check whether downstream consumers need to distinguish event categories for filtering, alerting, or investigation. If they do, a union is usually the safer model because it preserves the event’s identity instead of normalising it away.
Common mistake: Teams often add optional fields to an interface as soon as the logger must handle multiple cases. That is usually a sign the type is hiding a union-shaped problem, and it tends to weaken both code clarity and log quality.
Practitioner takeaway: Use an interface for the stable logging wrapper and a union for the event variants when you need the compiler to protect the meaning of each audit record.