Skip to content

unacy / WithUnits

Type Alias: WithUnits<T, M>

ts
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 ParameterDefault typeDescription
T-Base type (e.g., number, bigint, record, tuple, class instance)
M extends BaseMetadataBaseMetadataMetadata type (must extend BaseMetadata with required name property)

Example

typescript
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 error

Use 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

Released under the MIT License.