Skip to content

Commit 14df7d3

Browse files
authored
fix: fix unique method types (#457)
1 parent 2a4f835 commit 14df7d3

3 files changed

Lines changed: 52 additions & 28 deletions

File tree

src/unique.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as uniqueExec from './vendor/unique';
2+
import type { RecordKey } from './vendor/unique';
23

34
/**
45
* Module to generate unique entries.
@@ -38,20 +39,20 @@ export class Unique {
3839
* @param opts.compare The function used to determine whether a value was already returned.
3940
*
4041
* @example
41-
* faker.unique(faker.name.firstName())
42+
* faker.unique(faker.name.firstName)
4243
*/
43-
unique<Method extends (args: Args) => string, Args extends any[]>(
44+
unique<Method extends (...parameters) => RecordKey>(
4445
method: Method,
45-
args: Args,
46+
args?: Parameters<Method>,
4647
opts?: {
4748
startTime?: number;
4849
maxTime?: number;
4950
maxRetries?: number;
5051
currentIterations?: number;
51-
exclude?: string | string[];
52-
compare?: (obj: Record<string, string>, key: string) => 0 | -1;
52+
exclude?: RecordKey | RecordKey[];
53+
compare?: (obj: Record<RecordKey, RecordKey>, key: RecordKey) => 0 | -1;
5354
}
54-
): string {
55+
): ReturnType<Method> {
5556
opts = opts || {};
5657
opts.startTime = new Date().getTime();
5758
if (typeof opts.maxTime !== 'number') {

src/vendor/unique.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1+
export type RecordKey = string | number | symbol;
2+
13
// global results store
24
// currently uniqueness is global to entire faker instance
35
// this means that faker should currently *never* return duplicate values across all API methods when using `Faker.unique`
46
// it's possible in the future that some users may want to scope found per function call instead of faker instance
5-
const found: Record<string, string> = {};
7+
const found: Record<RecordKey, RecordKey> = {};
68

79
// global exclude list of results
810
// defaults to nothing excluded
9-
const exclude: string[] = [];
11+
const exclude: RecordKey[] = [];
1012

1113
// current iteration or retries of unique.exec ( current loop depth )
1214
const currentIterations = 0;
1315

1416
// uniqueness compare function
1517
// default behavior is to check value as key against object hash
16-
function defaultCompare<T, Key extends keyof T>(obj: T, key: Key): 0 | -1 {
18+
function defaultCompare(
19+
obj: Record<RecordKey, RecordKey>,
20+
key: RecordKey
21+
): 0 | -1 {
1722
if (typeof obj[key] === 'undefined') {
1823
return -1;
1924
}
@@ -42,20 +47,18 @@ function errorMessage(
4247
);
4348
}
4449

45-
// TODO @Shinigami92 2022-01-24: We should investigate deeper into the types
46-
// Especially the `opts.compare` parameter and `Result` type
47-
export function exec<Method extends (args: Args) => string, Args extends any[]>(
50+
export function exec<Method extends (...parameters) => RecordKey>(
4851
method: Method,
49-
args: Args,
52+
args: Parameters<Method>,
5053
opts: {
5154
maxTime?: number;
5255
maxRetries?: number;
53-
exclude?: string | string[];
54-
compare?: (obj: Record<string, string>, key: string) => 0 | -1;
56+
exclude?: RecordKey | RecordKey[];
57+
compare?: (obj: Record<RecordKey, RecordKey>, key: RecordKey) => 0 | -1;
5558
currentIterations?: number;
5659
startTime?: number;
5760
}
58-
): string {
61+
): ReturnType<Method> {
5962
const now = new Date().getTime();
6063

6164
opts = opts || {};
@@ -75,7 +78,7 @@ export function exec<Method extends (args: Args) => string, Args extends any[]>(
7578
const startTime = opts.startTime;
7679

7780
// support single exclude argument as string
78-
if (typeof opts.exclude === 'string') {
81+
if (!Array.isArray(opts.exclude)) {
7982
opts.exclude = [opts.exclude];
8083
}
8184

@@ -103,7 +106,7 @@ export function exec<Method extends (args: Args) => string, Args extends any[]>(
103106
}
104107

105108
// execute the provided method to find a potential satisfied value
106-
const result: string = method.apply(this, args);
109+
const result: ReturnType<Method> = method.apply(this, args);
107110

108111
// if the result has not been previously found, add it to the found array and return the value as it's unique
109112
if (

test/unique.spec.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,25 @@ const seededRuns = [
55
{
66
seed: 42,
77
expectations: {
8-
withMethod: 'Test-188',
8+
withCustomMethod: 'Test-188',
9+
withNumberMethod: 37454,
10+
withNumberMethodAndArgs: 19,
911
},
1012
},
1113
{
1214
seed: 1337,
1315
expectations: {
14-
withMethod: 'Test-132',
16+
withCustomMethod: 'Test-132',
17+
withNumberMethod: 26202,
18+
withNumberMethodAndArgs: 13,
1519
},
1620
},
1721
{
1822
seed: 1211,
1923
expectations: {
20-
withMethod: 'Test-465',
24+
withCustomMethod: 'Test-465',
25+
withNumberMethod: 92852,
26+
withNumberMethodAndArgs: 47,
2127
},
2228
},
2329
];
@@ -29,7 +35,7 @@ const MOCK_ARRAY = Array.from(
2935
(_, index) => `Test-${index + 1}`
3036
);
3137

32-
function method(prefix: string = ''): string {
38+
function customMethod(prefix: string = ''): string {
3339
const element = faker.random.arrayElement(MOCK_ARRAY);
3440
return `${prefix}${element}`;
3541
}
@@ -41,20 +47,34 @@ describe('unique', () => {
4147

4248
for (const { seed, expectations } of seededRuns) {
4349
describe(`seed: ${seed}`, () => {
44-
it(`unique(method)`, () => {
50+
it(`unique(customMethod)`, () => {
4551
faker.seed(seed);
4652

47-
const actual = faker.unique(method);
48-
expect(actual).toEqual(expectations.withMethod);
53+
const actual = faker.unique(customMethod);
54+
expect(actual).toEqual(expectations.withCustomMethod);
4955
});
5056

51-
it(`unique(method, args)`, () => {
57+
it(`unique(customMethod, args)`, () => {
5258
faker.seed(seed);
5359

5460
const prefix = 'prefix-1-';
5561

56-
const actual = faker.unique(method, [prefix]);
57-
expect(actual).toEqual(prefix + expectations.withMethod);
62+
const actual = faker.unique(customMethod, [prefix]);
63+
expect(actual).toEqual(prefix + expectations.withCustomMethod);
64+
});
65+
66+
it(`unique(() => number)`, () => {
67+
faker.seed(seed);
68+
69+
const actual = faker.unique(faker.datatype.number);
70+
expect(actual).toEqual(expectations.withNumberMethod);
71+
});
72+
73+
it(`unique(() => number), args)`, () => {
74+
faker.seed(seed);
75+
76+
const actual = faker.unique(faker.datatype.number, [50]);
77+
expect(actual).toEqual(expectations.withNumberMethodAndArgs);
5878
});
5979
});
6080
}

0 commit comments

Comments
 (0)