Skip to content

fix(types): stop LabelValues distributing over label-name unions - #862

Closed
cpruijsen wants to merge 1 commit into
prometheus:mainfrom
cpruijsen:fix/issue-861
Closed

cpruijsen wants to merge 1 commit into
prometheus:mainfrom
cpruijsen:fix/issue-861

Conversation

@cpruijsen

Copy link
Copy Markdown

Summary

Tuple-wrap both sides of the LabelValues check ([T] extends [NoLabelNameType]) so a multi-label get() keeps every declared key.

LabelValues<T> was a naked distributive conditional (T extends never). For a metric with two label names, LabelValues became a union of one-key objects, so const { values } = await counter.get(); values[0].labels.a failed to compile (TS2339) even though both keys were declared. The no-label never case resolves to Partial<Record<string, never>> (the empty-record type #655 intended; the naked form yielded never by distributing over the empty union).

test/typescript.ts reads .method and .status from a two-label Counter and Gauge get(). That access fails tsc on the old type.

Fixes #861.

Decision

Tuple-wrap both sides of the LabelValues check rather than revert to Partial<Record<T, string | number>> (prom-client 15.1.3). The tuple wrap is the form in the issue, and it keeps the no-label empty-record type from #655. Reverting would drop that branch.

Happy to switch if you would rather revert the alias, drop the changelog line, or also cover Histogram/Summary get() reads (same alias).

Test plan

  • npm run compile-typescript passes with the wrap.
  • Revert only the index.d.ts line; the new get() label reads fail tsc with TS2339 on the one-key union.
  • Restore the wrap; tsc is clean again.
  • npm run lint and npm run check-prettier pass.

A naked T extends never splits multi-label metrics into a union of
one-key objects, so reading labels back from get() keeps only one key.

Fixes #861

Signed-off-by: Christopher Pruijsen <christopher.pruijsen@gmail.com>
@cpruijsen

Copy link
Copy Markdown
Author

Closing this one. Not taking it further.

@cpruijsen cpruijsen closed this Oct 14, 2026
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.

TypeScript: LabelValues distributes over label-name unions, so labels from get() lose all but one key

1 participant