diff options
| author | ST-DDT <[email protected]> | 2024-02-25 22:05:57 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-02-25 22:05:57 +0100 |
| commit | c45537f6d4f3a28d8be1ebbe03567004c04af145 (patch) | |
| tree | d1f7081187aae812bb355004bbe46439c3094e5f | |
| parent | 64ff107b8a9cd0965a67f00fd30cded144c02fd6 (diff) | |
| download | faker-c45537f6d4f3a28d8be1ebbe03567004c04af145.tar.xz faker-c45537f6d4f3a28d8be1ebbe03567004c04af145.zip | |
feat(helpers)!: use const generics where possible (#2685)
| -rw-r--r-- | docs/guide/upgrading_v9/2685.md | 16 | ||||
| -rw-r--r-- | package.json | 9 | ||||
| -rw-r--r-- | src/modules/helpers/index.ts | 30 | ||||
| -rw-r--r-- | test/modules/helpers.spec-d.ts | 127 | ||||
| -rw-r--r-- | vitest.config.ts | 4 |
5 files changed, 165 insertions, 21 deletions
diff --git a/docs/guide/upgrading_v9/2685.md b/docs/guide/upgrading_v9/2685.md new file mode 100644 index 00000000..7e05fac6 --- /dev/null +++ b/docs/guide/upgrading_v9/2685.md @@ -0,0 +1,16 @@ +### Usage of TypeScript 5 Features + +_This upgrade is an extension to_ [#1953](./1953.md) + +The helpers module now uses TS5 features, so if you are using Faker with TypeScript, you must use TS5. + +```ts +// v8 +faker.helpers.arrayElement([1, 2, 3]); // number +faker.helpers.arrayElement([1, 2, 3] as const); // 1 | 2 | 3 + +// v9 +faker.helpers.arrayElement([1, 2, 3]); // 1 | 2 | 3 +``` + +If you are unable to upgrade to TS5, you have to keep using Faker v8. diff --git a/package.json b/package.json index 30752acf..d38da942 100644 --- a/package.json +++ b/package.json @@ -31,14 +31,7 @@ "type": "module", "main": "dist/index.cjs", "module": "dist/index.js", - "types": "index.d.ts", - "typesVersions": { - ">=4.0": { - "*": [ - "dist/types/*" - ] - } - }, + "types": "dist/types/index.d.ts", "exports": { ".": { "types": "./dist/types/index.d.ts", diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index a42da85f..593d1ede 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -633,7 +633,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 8.0.0 */ - shuffle<T>( + shuffle<const T>( list: T[], options: { /** @@ -659,7 +659,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 2.0.1 */ - shuffle<T>( + shuffle<const T>( list: ReadonlyArray<T>, options?: { /** @@ -686,7 +686,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 2.0.1 */ - shuffle<T>( + shuffle<const T>( list: T[], options?: { /** @@ -697,7 +697,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { inplace?: boolean; } ): T[]; - shuffle<T>(list: T[], options: { inplace?: boolean } = {}): T[] { + shuffle<const T>(list: T[], options: { inplace?: boolean } = {}): T[] { const { inplace = false } = options; if (!inplace) { @@ -734,7 +734,10 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 6.0.0 */ - uniqueArray<T>(source: ReadonlyArray<T> | (() => T), length: number): T[] { + uniqueArray<const T>( + source: ReadonlyArray<T> | (() => T), + length: number + ): T[] { if (Array.isArray(source)) { const set = new Set<T>(source); const array = [...set]; @@ -813,7 +816,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 6.3.0 */ - maybe<TResult>( + maybe<const TResult>( callback: () => TResult, options: { /** @@ -845,7 +848,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 6.3.0 */ - objectKey<T extends Record<string, unknown>>(object: T): keyof T { + objectKey<const T extends Record<string, unknown>>(object: T): keyof T { const array: Array<keyof T> = Object.keys(object); return this.arrayElement(array); } @@ -864,7 +867,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 6.3.0 */ - objectValue<T extends Record<string, unknown>>(object: T): T[keyof T] { + objectValue<const T extends Record<string, unknown>>(object: T): T[keyof T] { const key = this.faker.helpers.objectKey(object); return object[key]; } @@ -883,7 +886,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 8.0.0 */ - objectEntry<T extends Record<string, unknown>>( + objectEntry<const T extends Record<string, unknown>>( object: T ): [keyof T, T[keyof T]] { const key = this.faker.helpers.objectKey(object); @@ -904,7 +907,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 6.3.0 */ - arrayElement<T>(array: ReadonlyArray<T>): T { + arrayElement<const T>(array: ReadonlyArray<T>): T { // TODO @xDivisionByZerox 2023-04-20: Remove in v9 if (array == null) { throw new FakerError( @@ -941,7 +944,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 8.0.0 */ - weightedArrayElement<T>( + weightedArrayElement<const T>( array: ReadonlyArray<{ /** * The weight of the value. @@ -1000,7 +1003,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 6.3.0 */ - arrayElements<T>( + arrayElements<const T>( array: ReadonlyArray<T>, count?: | number @@ -1074,6 +1077,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 8.0.0 */ + // This does not use `const T` because enums shouldn't be created on the spot. enumValue<T extends Record<string | number, string | number>>( enumObject: T ): T[keyof T] { @@ -1134,7 +1138,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { * * @since 8.0.0 */ - multiple<TResult>( + multiple<const TResult>( method: () => TResult, options: { /** diff --git a/test/modules/helpers.spec-d.ts b/test/modules/helpers.spec-d.ts new file mode 100644 index 00000000..11ce8c88 --- /dev/null +++ b/test/modules/helpers.spec-d.ts @@ -0,0 +1,127 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { faker } from '../../src'; + +describe('helpers', () => { + describe('shuffle', () => { + describe('inplace: true', () => { + it('const generic single element', () => { + const actual = faker.helpers.shuffle([1], { inplace: true }); + expectTypeOf(actual).toEqualTypeOf<Array<1>>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.shuffle([1, 'a', false], { + inplace: true, + }); + expectTypeOf(actual).toEqualTypeOf<Array<1 | 'a' | false>>(); + }); + }); + + describe('inplace: false', () => { + it('const generic single element', () => { + const actual = faker.helpers.shuffle([1], { inplace: false }); + expectTypeOf(actual).toEqualTypeOf<Array<1>>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.shuffle([1, 'a', false], { + inplace: false, + }); + expectTypeOf(actual).toEqualTypeOf<Array<1 | 'a' | false>>(); + }); + }); + }); + + describe('uniqueArray', () => { + it('const generic single element', () => { + const actual = faker.helpers.uniqueArray([1], 1); + expectTypeOf(actual).toEqualTypeOf<Array<1>>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.uniqueArray([1, 'a', false], 3); + expectTypeOf(actual).toEqualTypeOf<Array<1 | 'a' | false>>(); + }); + }); + + describe('maybe', () => { + it('const generic single element', () => { + // TODO @ST-DDT 2024-02-25: Check why this is detected as `number` instead of `1` + const actual = faker.helpers.maybe(() => 1); + expectTypeOf(actual).toEqualTypeOf<number | undefined>(); + }); + }); + + describe('objectKey', () => { + it('const generic single element', () => { + const actual = faker.helpers.objectKey({ a: 1 }); + expectTypeOf(actual).toEqualTypeOf<'a'>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.objectKey({ a: 1, b: 'a', c: false }); + expectTypeOf(actual).toEqualTypeOf<'a' | 'b' | 'c'>(); + }); + }); + + describe('objectValue', () => { + it('const generic single element', () => { + const actual = faker.helpers.objectValue({ a: 1 }); + expectTypeOf(actual).toEqualTypeOf<1>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.objectValue({ a: 1, b: 'a', c: false }); + expectTypeOf(actual).toEqualTypeOf<1 | 'a' | false>(); + }); + }); + + describe('objectEntry', () => { + it('const generic single element', () => { + const actual = faker.helpers.objectEntry({ a: 1 }); + expectTypeOf(actual).toEqualTypeOf<['a', 1]>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.objectEntry({ a: 1, b: 'a', c: false }); + // TODO @ST-DDT 2024-02-25: Check whether we can infer the return type any better + expectTypeOf(actual).toEqualTypeOf<['a' | 'b' | 'c', false | 1 | 'a']>(); + }); + }); + + describe('arrayElement', () => { + it('const generic single element', () => { + const actual = faker.helpers.arrayElement([1]); + expectTypeOf(actual).toEqualTypeOf<1>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.arrayElement([1, 'a', false]); + expectTypeOf(actual).toEqualTypeOf<1 | 'a' | false>(); + }); + }); + + describe('arrayElements', () => { + it('const generic single element', () => { + const actual = faker.helpers.arrayElements([1], 1); + expectTypeOf(actual).toEqualTypeOf<Array<1>>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.arrayElements([1, 'a', false], 3); + expectTypeOf(actual).toEqualTypeOf<Array<1 | 'a' | false>>(); + }); + }); + + describe('multiple', () => { + it('const generic single element', () => { + const actual = faker.helpers.multiple(() => 1); + expectTypeOf(actual).toEqualTypeOf<number[]>(); + }); + + it('const generic multiple elements', () => { + const actual = faker.helpers.multiple(() => 1, { count: 3 }); + expectTypeOf(actual).toEqualTypeOf<number[]>(); + }); + }); +}); diff --git a/vitest.config.ts b/vitest.config.ts index e903e970..2bac6031 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -19,6 +19,10 @@ export default defineConfig({ seed: VITEST_SEQUENCE_SEED, shuffle: true, }, + typecheck: { + enabled: true, + include: ['test/**/*.spec-d.ts'], + }, onConsoleLog(log, type) { if ( type === 'stderr' && |
