unacy / WithUnits
Type Alias: WithUnits<T, M>
type WithUnits<T, M> = Tagged<T, typeof UNITS, M>;Defined in: packages/core/src/types.ts:134
Brand a value with a unit identifier for compile-time unit safety.
The branding is purely a compile-time phantom — at runtime, values are plain T (number, string, etc.) with zero overhead. Branded values extend their base type, so they are assignable to plain T but not vice versa.
Type Parameters
| Type Parameter | Default type | Description |
|---|---|---|
T | - | Base type (e.g., number, bigint, record, tuple, class instance) |
M extends BaseMetadata | BaseMetadata | Metadata type (must extend BaseMetadata with required name property) |
Example
const CelsiusMeta = { name: 'Celsius' as const, symbol: '°C' } satisfies BaseMetadata;
type Celsius = WithUnits<number, typeof CelsiusMeta>;
const temp: Celsius = 25 as Celsius;
// Celsius is assignable to number, but number is not assignable to Celsius
const raw: number = temp; // OK
const invalid: Celsius = raw; // TS errorUse When
You need a branded unit type and your metadata does not have a type field (or you want to specify the base type explicitly).
Avoid When
Your metadata already carries a type field — prefer WithTypedUnits<M> to let the compiler infer the correct base type automatically.
Pitfalls
NEVER use as to cast a plain number to WithUnits<number, M> in application code without validating the value first — the cast bypasses every compile-time guarantee that WithUnits provides.
NEVER assign a value of WithUnits<number, CelsiusMetadata> to a variable typed WithUnits<number, FahrenheitMetadata> via as — the phantom types become meaningless if the brand is forged at assignment sites.
See
WithTypedUnits