aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpomali <[email protected]>2024-03-03 11:12:17 +0100
committerGitHub <[email protected]>2024-03-03 11:12:17 +0100
commit2b15f2ee7eeba7147c75a24d71042ee996966c92 (patch)
tree2812cdda5e77ae70cc5038ee659745fa130c22ac
parent9348138893bb95faa5037c653443fbd525ce2939 (diff)
downloadfaker-2b15f2ee7eeba7147c75a24d71042ee996966c92.tar.xz
faker-2b15f2ee7eeba7147c75a24d71042ee996966c92.zip
feat(helpers)!: stricter checking for function signature passed to `multiple` (#2563)
Co-authored-by: ST-DDT <[email protected]> Co-authored-by: Matt Mayer <[email protected]>
-rw-r--r--docs/guide/upgrading_v9/2563.md38
-rw-r--r--src/modules/helpers/index.ts8
-rw-r--r--test/modules/__snapshots__/helpers.spec.ts.snap24
-rw-r--r--test/modules/helpers.spec.ts41
4 files changed, 97 insertions, 14 deletions
diff --git a/docs/guide/upgrading_v9/2563.md b/docs/guide/upgrading_v9/2563.md
new file mode 100644
index 00000000..da770de9
--- /dev/null
+++ b/docs/guide/upgrading_v9/2563.md
@@ -0,0 +1,38 @@
+### Stricter checking for function signature passed to `faker.helpers.multiple` method
+
+The `faker.helpers.multiple` method takes a function reference as its first parameter. Previously you may have written code like this to generate multiple values.
+
+```ts
+faker.helpers.multiple(faker.date.past, { count: 2 });
+```
+
+However this code has a bug - `faker.helpers.multiple` passes the loop index as the second parameter to the method, which in this case would set the `refDate` of the `faker.date.past()` call to 0, making all dates before 1970.
+
+Instead you should generally use a lambda function like
+
+```ts
+faker.helpers.multiple(() => faker.date.past(), { count: 2 });
+```
+
+to get the desired behavior. In v9.0, we use stricter type-checking in Typescript to detect when a function is called which is not compatible with `(v: unknown, index: number)` which can cause compile-time errors in places where previously there were potential runtime errors.
+
+**Bad**
+
+```ts
+faker.helpers.multiple(faker.person.firstName, ...); // ❗
+// In Typescript, this is now a compile time error
+// Argument of type '(sex?: "female" | "male" | undefined) => string'
+// is not assignable to parameter of type '(v: unknown, index: number) => unknown'.
+```
+
+**Good**
+
+```ts
+faker.helpers.multiple(() => faker.person.firstName(), ...); // ✔
+```
+
+The new types also allow for easier use-cases where the index is part of the generated data e.g. as id.
+
+```ts
+faker.helpers.multiple((_, index) => ({ id: index, ...}), ...); // [{id: 0, ...}, ...]
+```
diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts
index 593d1ede..b21f13e7 100644
--- a/src/modules/helpers/index.ts
+++ b/src/modules/helpers/index.ts
@@ -1129,17 +1129,19 @@ export class SimpleHelpersModule extends SimpleModuleBase {
* @template TResult The type of elements.
*
* @param method The method used to generate the values.
+ * The method will be called with `(_, index)`, to allow using the index in the generated value e.g. as id.
* @param options The optional options object.
* @param options.count The number or range of elements to generate. Defaults to `3`.
*
* @example
- * faker.helpers.multiple(faker.person.firstName) // [ 'Aniya', 'Norval', 'Dallin' ]
- * faker.helpers.multiple(faker.person.firstName, { count: 3 }) // [ 'Santos', 'Lavinia', 'Lavinia' ]
+ * faker.helpers.multiple(() => faker.person.firstName()) // [ 'Aniya', 'Norval', 'Dallin' ]
+ * faker.helpers.multiple(() => faker.person.firstName(), { count: 3 }) // [ 'Santos', 'Lavinia', 'Lavinia' ]
+ * faker.helpers.multiple((_, i) => `${faker.color.human()}-${i + 1}`) // [ 'orange-1', 'orchid-2', 'sky blue-3' ]
*
* @since 8.0.0
*/
multiple<const TResult>(
- method: () => TResult,
+ method: (v: unknown, index: number) => TResult,
options: {
/**
* The number or range of elements to generate.
diff --git a/test/modules/__snapshots__/helpers.spec.ts.snap b/test/modules/__snapshots__/helpers.spec.ts.snap
index af17437a..8ecb47a8 100644
--- a/test/modules/__snapshots__/helpers.spec.ts.snap
+++ b/test/modules/__snapshots__/helpers.spec.ts.snap
@@ -98,6 +98,14 @@ exports[`helpers > 42 > multiple > with method and count range 1`] = `
]
`;
+exports[`helpers > 42 > multiple > with method using index 1`] = `
+[
+ 0,
+ 3,
+ 6,
+]
+`;
+
exports[`helpers > 42 > multiple > with only method 1`] = `
[
3373557479352566,
@@ -330,6 +338,14 @@ exports[`helpers > 1211 > multiple > with method and count range 1`] = `
]
`;
+exports[`helpers > 1211 > multiple > with method using index 1`] = `
+[
+ 0,
+ 3,
+ 6,
+]
+`;
+
exports[`helpers > 1211 > multiple > with only method 1`] = `
[
8363366038243348,
@@ -544,6 +560,14 @@ exports[`helpers > 1337 > multiple > with method and count range 1`] = `
]
`;
+exports[`helpers > 1337 > multiple > with method using index 1`] = `
+[
+ 0,
+ 3,
+ 6,
+]
+`;
+
exports[`helpers > 1337 > multiple > with only method 1`] = `
[
2360108457524098,
diff --git a/test/modules/helpers.spec.ts b/test/modules/helpers.spec.ts
index 1ba43c70..5a2294bb 100644
--- a/test/modules/helpers.spec.ts
+++ b/test/modules/helpers.spec.ts
@@ -173,11 +173,14 @@ describe('helpers', () => {
});
t.describe('multiple', (t) => {
- t.it('with only method', faker.number.int)
- .it('with method and count', faker.number.int, { count: 5 })
- .it('with method and count range', faker.number.int, {
+ t.it('with only method', () => faker.number.int())
+ .it('with method and count', () => faker.number.int(), {
+ count: 5,
+ })
+ .it('with method and count range', () => faker.number.int(), {
count: { min: 1, max: 10 },
- });
+ })
+ .it('with method using index', (_, i) => i * 3);
});
});
@@ -1144,30 +1147,46 @@ describe('helpers', () => {
describe('multiple()', () => {
it('should generate values from the function with a default length of 3', () => {
- const result = faker.helpers.multiple(faker.person.firstName);
+ const result = faker.helpers.multiple(() => faker.person.firstName());
expect(result).toBeTypeOf('object');
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(3);
});
it('should generate the given amount of values from the function', () => {
- const result = faker.helpers.multiple(faker.person.firstName, {
- count: 5,
- });
+ const result = faker.helpers.multiple(
+ () => faker.person.firstName(),
+ {
+ count: 5,
+ }
+ );
expect(result).toBeTypeOf('object');
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(5);
});
it('should generate a ranged number of values from the function', () => {
- const result = faker.helpers.multiple(faker.person.firstName, {
- count: { min: 1, max: 10 },
- });
+ const result = faker.helpers.multiple(
+ () => faker.person.firstName(),
+ {
+ count: { min: 1, max: 10 },
+ }
+ );
expect(result).toBeTypeOf('object');
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBeGreaterThanOrEqual(1);
expect(result.length).toBeLessThanOrEqual(10);
});
+
+ it('should generate values using index of created value', () => {
+ const result = faker.helpers.multiple((_, i) => i * 2, {
+ count: 3,
+ });
+ expect(result).toBeTypeOf('object');
+ expect(Array.isArray(result)).toBe(true);
+ expect(result.length).toBe(3);
+ expect(result).toStrictEqual([0, 2, 4]);
+ });
});
}
);