Skip to content

fix(types): make MetricType a string union matching runtime values - #790

Open
milcho0604 wants to merge 1 commit into
prometheus:mainfrom
milcho0604:fix/metrictype-string-union
Open

fix(types): make MetricType a string union matching runtime values#790
milcho0604 wants to merge 1 commit into
prometheus:mainfrom
milcho0604:fix/metrictype-string-union

Conversation

@milcho0604

Copy link
Copy Markdown
Contributor

Fixes #336

index.d.ts declares MetricType as a numeric enum, but no such object is exported at runtime — require('prom-client').MetricType is undefined, so MetricType.Counter type-checks and then throws when evaluated. Meanwhile the property it describes, MetricObject.type, is a runtime string ('counter', 'gauge', 'histogram', 'summary' — set in lib/counter.js, lib/gauge.js, lib/histogram.js, lib/summary.js). Both halves were diagnosed in #336 back in 2020.

This models it the way the neighbouring Aggregator type already models the same situation — a string-literal union of the runtime values:

export type MetricType = 'counter' | 'gauge' | 'histogram' | 'summary';

Why not the alternatives: a declaration-only enum with string values would still claim a runtime object exists (the crash stays), and shipping a runtime object would add new JS API solely to rehabilitate one that never worked. The union just describes what the library returns.

What changes for consumers (declaration-only; index.js is untouched):

  • Type-position uses keep compiling.
  • Comparing a reported type against its actual value (m.type === 'counter') now type-checks and narrows — with the numeric enum this comparison was itself a compile error (TS2367, no overlap), forcing casts.
  • Value-style access (MetricType.Counter) stops compiling (TS2693) — it previously threw at runtime.
  • Under verbatimModuleSyntax, importing MetricType now requires import type.

Tests (test/typescript.ts, compiled by tsc --project . in CI):

  • type-position use, and narrowing of a reported metric type;
  • an exhaustive switch that fails to compile if the union and the member list drift apart in either direction (verified by mutation: removing 'gauge' → TS2678, adding a member → TS2322 on the never default);
  • a @ts-expect-error guard on MetricType.Counter — if a value declaration for MetricType is ever introduced, the directive turns unused and the compile fails, flagging the test for update.

Since Unreleased already carries breaking changes for the first release under the Prometheus umbrella, this seemed like the right window for a type-level break; the CHANGELOG entry is under Breaking.

The declaration file declares MetricType as a numeric enum, but no such
object is exported at runtime: require('prom-client').MetricType is
undefined, so value-style uses like MetricType.Counter type-check and
then throw TypeError when evaluated (prometheus#336, diagnosed in 2020). Meanwhile
the property it describes (MetricObject.type) is a runtime string:
'counter', 'gauge', 'histogram' or 'summary'.

Model it the way the neighbouring Aggregator type already models the
same situation: a string-literal union of the runtime values. A
declaration-only enum with string values would still claim a runtime
object exists, and adding a runtime object would introduce new JS API
solely to rehabilitate one that never worked - the union models what the
library actually returns. index.js is untouched. Type-position uses keep
compiling, comparisons against reported metric types now type-check and
narrow correctly (with the numeric enum, m.type === 'counter' was itself
a compile error), and value-style access fails at compile time instead
of at runtime.

Fixes prometheus#336

Signed-off-by: Changhyun Kim <milcho0604@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MetricType enum not exported for use in index.js

1 participant