Skip to content

feat: introduce NumberRange type#3838

Draft
Shinigami92 wants to merge 1 commit into
nextfrom
feat-add-NumberRange-type
Draft

feat: introduce NumberRange type#3838
Shinigami92 wants to merge 1 commit into
nextfrom
feat-add-NumberRange-type

Conversation

@Shinigami92
Copy link
Copy Markdown
Member

--> DRAFTING <--

@Shinigami92 Shinigami92 self-assigned this May 2, 2026
@netlify
Copy link
Copy Markdown

netlify Bot commented May 2, 2026

Deploy Preview for fakerjs ready!

Name Link
🔨 Latest commit c4a4376
🔍 Latest deploy log https://app.netlify.com/projects/fakerjs/deploys/69f5c7f0ec52ab000811dc4f
😎 Deploy Preview https://deploy-preview-3838.fakerjs.dev
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.90%. Comparing base (e68db50) to head (c4a4376).
⚠️ Report is 14 commits behind head on next.

Additional details and impacted files
@@            Coverage Diff             @@
##             next    #3838      +/-   ##
==========================================
+ Coverage   98.84%   98.90%   +0.06%     
==========================================
  Files         899      899              
  Lines        3113     3105       -8     
  Branches      574      550      -24     
==========================================
- Hits         3077     3071       -6     
+ Misses         32       30       -2     
  Partials        4        4              
Files with missing lines Coverage Δ
src/modules/airline/index.ts 100.00% <ø> (ø)
src/modules/date/index.ts 100.00% <ø> (ø)
src/modules/finance/bitcoin.ts 100.00% <ø> (ø)
src/modules/helpers/index.ts 95.27% <100.00%> (ø)
src/modules/lorem/index.ts 100.00% <100.00%> (ø)
src/modules/string/index.ts 100.00% <100.00%> (ø)
src/modules/system/index.ts 100.00% <ø> (ø)
src/modules/word/filter-word-list-by-length.ts 100.00% <100.00%> (ø)
src/modules/word/index.ts 96.00% <ø> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Shinigami92
Copy link
Copy Markdown
Member Author

@ST-DDT @xDivisionByZerox — looking for input on a tradeoff this PR introduces.

Context

This PR replaces ~40 inline { min: number; max: number } shapes with a shared NumberRange interface. As a side effect, the per-site type-level JSDoc on min/max (e.g. "The minimum number of words to generate.") is gone. The method-level @param wordCount.min / @param wordCount.max lines are still there, but the JSDoc that surfaces in VSCode hover on the field itself is now the generic NumberRange description ("The minimum value (inclusive).").

Options

1. Per-concept named ranges

Define small types per use-case, each carrying its own JSDoc:

export interface WordCount extends NumberRange {
  /** The minimum number of words to generate. */
  min: number;
  /** The maximum number of words to generate. */
  max: number;
}
  • ✅ Tooltips recovered, semantically meaningful named types for consumers.
  • ❌ ~10 new exported types; API surface grows.

2. Hybrid: inline shape for surface methods, NumberRange internally

Keep NumberRange for plumbing (helpers.rangeToNumber, helpers.multiple) and revert to inline { /** doc */ min; /** doc */ max } on user-facing methods (lorem.words, string.alpha, …).

  • ✅ Pragmatic — best tooltips where users actually hover.
  • ❌ Inconsistent style across the codebase.

3. Accept it, lean on @param

Ship as-is. TS LSP can surface @param x.min JSDoc on destructured fields in some cases, and the rendered docs site has the info via @param.

  • ✅ Smallest diff, simplest.
  • ❌ Tooltip regression in VSCode for the inline { min, max } form.

4. Re-declare min / max inline on each method, typed as NumberRange-compatible

words(
  wordCount: number | (NumberRange & {
    /** The minimum number of words to generate. */
    min: number;
    /** The maximum number of words to generate. */
    max: number;
  }) = 3
): string;
  • NumberRange stays publicly importable for consumers, no per-concept type explosion, per-method tooltips preserved.
  • ❌ The methods themselves don't gain dedup — each still re-declares min/max with JSDoc; NumberRange is more of a public-API contract than an implementation deduplication.

My take

I lean toward option 4: it keeps NumberRange publicly available for consumers (which is part of the point per #1443), doesn't bloat the API with a specific type for every method, and we still get the tooltip docs at hover sites.

However it extends the tooltip, not overrides it:

Option 1 is also acceptable as a fallback — it gives consumers semantically meaningful types — but I'd rather have one shared NumberRange than ten specific ones.

It does not have the extended JSDoc, but only the specific (which might be a pro-argument for this option)

I don't like option 2: the inconsistency between "surface" and "internal" methods feels like a smell to me.

I don't like option 3: the per-site tooltip docs were an intentional team decision earlier, and I don't want to silently regress that.

Thoughts?

@Shinigami92 Shinigami92 added s: needs decision Needs team/maintainer decision c: feature Request for new feature labels May 2, 2026
@ST-DDT
Copy link
Copy Markdown
Member

ST-DDT commented May 2, 2026

IMO The most important benefit of this change is the shortened method signature => simplified readability.
Most users understand what a range is.

There are a few questions that we need to search answers for first:

A) Do our users understand that a range is {min, max} and NOT [min, max] with minimal effort?

  • If they need to see that it is an object at first glance, then this PR is obsolete.
  • If not and hovering the type is acceptable, then we should decide B+C

B) Do our users have a need for types or do they inline the arguments anyway?
Are our users likely to use our type, instead of declaring their own?
Do we do it for the readability of our signature?

C) Is the context closeness of numberRange.min/max important to our users?
aka do they need to know that it is a WordRange vs a number Range?


  1. IMO this kind of defeats the purpose of this change.
    If needed, our users can create a type for all our parameters themselves (either manually or via Parameters)
    The parameter itself is called wordCount with type NumberRange, IMO it is clear what it does.
    If we go that route anyway, then we should keep the Range as part of the name.

  2. Maybe. IMO this is the smallest and least interruptive. However the benefit is likely negible.
    Depends on (C): If it is important, then this maybe the max extend this PR can go.
    Our users are still able to use our conviencience type. Even if there is no direct link between the two.
    Though I doubt, that anyone will (know of and) use the NumberRange conviencience type then and instead users might define their own copy of the type or access it directly via Parameters[0].
    Also we should keep compatibility with that type in mind when implementing more features.

  3. Maybe.
    Depends on (C): If it is not important, then this is what we should do.
    This would be my recommended way.

  4. No. This negatively impacts readability of the signature. Especially the multiple unions and joins increase mental complexity quite a bit.

  5. "Keep as is in next"
    This would be my next recommendation in line.

Order of preference: 3, 5, 2, 1, 4
(3, 5, 2 are close together in preference, and they mostly depend on the goal of/requirements behind this change)


Diff-Preview

The current apidoc generation process does not display. Min and max params anymore:

Old New
grafik grafik
grafik grafik

Note: when the range currently has a default for either value, then we no longer display it in the jsdocs after this PR is merged.


I don't like option 3: the per-site tooltip docs were an intentional team decision earlier, and I don't want to silently regress that.

Isn't the whole point of this issue/PR to rethink this? If not, what is it?


@Shinigami92
Copy link
Copy Markdown
Member Author

@ST-DDT thanks for the feedback 👍

Isn't the whole point of this issue/PR to rethink this? If not, what is it?

The most valueable feature for consumers would be to use

import { type NumberRange, faker} from '@faker-js/faker';

const options: NumberRange = {
//             ^^^^^^^^^^^
  min: 1,
  max: 10
};

//                   vvvvvvv passing typed options
faker.module.method1(options)
faker.module.method2(options)
faker.module.method3(options)

So thinking about this, it would indeed be the best option to use Option 1, even when this is a bit verbose on our side.

@Shinigami92
Copy link
Copy Markdown
Member Author

Shinigami92 commented May 2, 2026

The workaround right now is something very complex like:

import { faker } from '@faker-js/faker';

type NumberRange = Exclude<Parameters<faker.module.method>[0], number>

pseudo code, not tested

@ST-DDT
Copy link
Copy Markdown
Member

ST-DDT commented May 2, 2026

So thinking about this, it would indeed be the best option to use Option 1, even when this is a bit verbose on our side.

Why do you think this distinction is important for our users?

const options: NumberRange = {
  min: 1,
  max: 10
};

faker.module.method1(options)
faker.module.method2(options)
faker.module.method3(options)

vs

const options: WordCountRange = {
  min: 1,
  max: 10
};

faker.module.method1(options)
faker.module.method2(options)
faker.module.method3(options)

IMO both types are identical. And adding more imports/different types just increases the mental costs to remember how they are defined.

@Shinigami92
Copy link
Copy Markdown
Member Author

You are right on the first look, but when in an IDE the second one (WordCountRange) will give the min and max a specific tooltip, instead of a generic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c: feature Request for new feature s: needs decision Needs team/maintainer decision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants