Documentation / Ressources / Explications / The type system

The type system

Meridian's engine ships with no clinical types. Instead it ships a language for describing types — a small meta type-system — and three open registries that plugins fill at startup. Everything downstream (connection validity, runtime checking, editor tooltips) is derived from those descriptors. This is the same "empty core" principle that governs the rest of the platform (see Architecture).

This document explains the model and why it is shaped this way. For the exhaustive variant table, see the TypeRef reference; for the registry APIs, see Type-system registries.

TypeRef: describing a shape

Every port and every field declares its shape with a recursive TypeRef (libs/shared/src/domain/types.ts). There are seven variants:

  • primitive — a scalar (Decimal, Text, Integer, Boolean, DateTime).
  • coded — a code bound to a terminology (a value-set).
  • quantity — a dimension-aware measurement, unit-checked against UCUM.
  • object — a structured datatype or resource from the registry.
  • ref — a reference to an entity.
  • list — a homogeneous collection.
  • any — a flow port whose type is inferred from what it is wired to.

The point of a closed set of variants over an open set of registered vocabularies: the engine understands the seven ways a shape can be composed, while knowing nothing about which concrete objects, code systems, or dimensions exist. A plugin adds Observation or renal-stage; the engine already knows how to compare, validate, and display anything expressed with them.

Three open registries

The vocabulary lives in three registries, all empty at boot:

  • OBJECT_TYPES — descriptors for object types (datatypes, clinical resources), filled by registerType.
  • VALUE_SETS — terminologies backing coded types, filled by registerValueSet. A value-set may be external: true: its concepts are not enumerated but resolved by a terminology server through the terminology port.
  • DIMENSIONS — physical dimensions backing quantity types (a canonical unit plus conversion factors), filled by registerDimension.

A plugin populates these during loading, in dependency order, so a value-set or type is always registered before a node that references it.

What the engine derives

From these descriptors alone, three capabilities fall out for free — no per-type code:

  • Structural compatibility of connections — subtyping by fields, by value-set, and by dimension (type-system.ts). This is what lets the editor reject an incompatible wire before a run (see Two levels of validation).
  • Runtime value validation at every port boundary.
  • Field metadata exported as JSON for the UX (tooltips, dropdowns, the palette).

No clinical TypeScript in the core

The core hosts no clinical TypeScript interface. A plugin that wants local static typing for its own behavior code generates it from its manifest (import type declarations, erased at runtime — e.g. external-plugins/demo/generated/types.ts). The result is zero coupling: the engine depends on the descriptors, never on a plugin's compiled types. See Codegen internals for how that projection works.

75 documents4 sectionssource : /docs · généré au build