javascriptfaker.js

faker.helpers.unique(faker.datatype.number, options) does NOT honor submitted options


Objective

I want to use @faker-js/faker's helpers.unique() function to generate an array of unique integers with a specified min and max. According to their docs, I should be able to do something like:

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

// extract the functions I plan to use (to make the next part more readable)
const { helpers: { unique }, datatype: { number } } = faker

// create array of 10 `undefined` elements and replace them with unique numbers
const numbers = Array.from({ length: 10 }).map(() => unique(number, { min: 1, max: 10 }))

// EXPECTED output
console.log(numbers) // [5, 2, 4, 10, 8, 9, 1, 7, 3, 6]

// ACTUAL output
console.log(numbers) // [17530, 15198, 10760, 38070, 84874, 89011, 4254, 43244, 21142, 79435]

What I've Tried

Here are my various attempts to figure out what's going on:

// actual output same as above
const options = { max: 10, min: 1 } // save options in a var in same order as docs
const numbers = Array.from({ length: 10 }).map(() => unique(number, options))

// try submitting options as separate params => ERROR (as expected)
const numbers = Array.from({ length: 10 }).map(() => unique(number, 10, 1))

// calling OUTSIDE of the `map()` function
unique(f.datatype.number, {min: 1, max: 10}) // yields e.g. 47858

// calling just `number()` to make sure it honors options if called normally
number({ min: 1, max: 10 }) // correctly returns integers between 1 and 10

Also, searched for "unique" on @faker-js/faker repo and discovered that the helpers.unique() function is slated for deprecation in v8.x as of 2023-01-27 (last week at time of writing this).

I'll leave this question here since it's already written and somebody might know the answer, and it might be useful to people continuing to use <= v7.6.


Solution

  • Faker's unique and datatype.number has been deprecated.

    You can use enforce-unique package for uniqueness check and you can use faker.number.int() for your number.

    import { faker } from '@faker-js/faker'
    import { UniqueEnforcer } from 'enforce-unique'
    
    const uniqueEnforcerNumber = new UniqueEnforcer()
    
    const numbers = Array.from({ length: 10 }).map(() => {
      return uniqueEnforcerNumber.enforce(() => {
        return faker.number.int({
          min: 1,
          max: 10,
        })
      })
    })
    
    // This will output
    // [5, 2, 4, 10, 8, 9, 1, 7, 3, 6]
    console.log(numbers)
    

    Check documentation for details