Skip to content

Commit

Permalink
types(vest): Set Callback as the last suite generic
Browse files Browse the repository at this point in the history
  • Loading branch information
ealush committed May 21, 2023
1 parent d437a03 commit a59066f
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ const suite = () =>
});

let validate: vest.Suite<
({ skip, skipGroup }: SuiteParams) => void,
TFieldName,
TGroupName
TGroupName,
({ skip, skipGroup }: SuiteParams) => void
>;
let callback_1 = jest.fn(),
callback_2 = jest.fn(),
Expand Down
9 changes: 5 additions & 4 deletions packages/vest/src/suite/SuiteTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
import { TTypedMethods } from 'getTypedMethods';
import { SuiteSelectors } from 'suiteSelectors';

export type Suite<T extends CB, F extends TFieldName, G extends TGroupName> = ((
...args: Parameters<T>
) => SuiteRunResult<F, G>) &
SuiteMethods<F, G>;
export type Suite<
F extends TFieldName,
G extends TGroupName,
T extends CB = CB
> = ((...args: Parameters<T>) => SuiteRunResult<F, G>) & SuiteMethods<F, G>;

export type SuiteMethods<F extends TFieldName, G extends TGroupName> = {
get: () => SuiteResult<F, G>;
Expand Down
5 changes: 2 additions & 3 deletions packages/vest/src/suite/__tests__/typedSuite.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { TTestSuiteCallback } from 'testUtils/TVestMock';
import * as vest from 'vest';

type TestFields = 'F1' | 'F2' | 'F3';
type TestGroups = 'G1' | 'G2' | 'G3';

describe('typed suite', () => {
let suite: vest.Suite<TTestSuiteCallback, TestFields, TestGroups>;
let suite: vest.Suite<TestFields, TestGroups>;

beforeEach(() => {
suite = vest.create(() => {});
Expand Down Expand Up @@ -70,7 +69,7 @@ describe('typed suite', () => {

describe('typed methods', () => {
it('should run the typed suite normally', () => {
const suite = vest.create<() => void, 'USERNAME' | 'PASSWORD'>(() => {
const suite = vest.create<'USERNAME' | 'PASSWORD'>(() => {
only('PASSWORD');

test('PASSWORD', 'password is too short', () => false);
Expand Down
18 changes: 9 additions & 9 deletions packages/vest/src/suite/createSuite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@ import { bindSuiteSelectors } from 'suiteSelectors';
import { validateSuiteCallback } from 'validateSuiteParams';

function createSuite<
T extends CB,
F extends TFieldName = string,
G extends TGroupName = string
>(suiteName: SuiteName, suiteCallback: T): Suite<T, F, G>;
G extends TGroupName = string,
T extends CB = CB
>(suiteName: SuiteName, suiteCallback: T): Suite<F, G, T>;
function createSuite<
T extends CB,
F extends TFieldName = string,
G extends TGroupName = string
>(suiteCallback: T): Suite<T, F, G>;
G extends TGroupName = string,
T extends CB = CB
>(suiteCallback: T): Suite<F, G, T>;
// @vx-allow use-use
function createSuite<
T extends CB,
F extends TFieldName = string,
G extends TGroupName = string
G extends TGroupName = string,
T extends CB = CB
>(
...args: [suiteName: SuiteName, suiteCallback: T] | [suiteCallback: T]
): Suite<T, F, G> {
): Suite<F, G, T> {
const [suiteCallback, suiteName] = args.reverse() as [T, SuiteName];

validateSuiteCallback(suiteCallback);
Expand Down
12 changes: 6 additions & 6 deletions packages/vest/src/suite/staticSuite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ import { createSuite } from 'createSuite';
import { TTypedMethods, getTypedMethods } from 'getTypedMethods';

export function staticSuite<
T extends CB,
F extends TFieldName = string,
G extends TGroupName = string
>(suiteCallback: T): StaticSuite<T, F, G> {
G extends TGroupName = string,
T extends CB = CB
>(suiteCallback: T): StaticSuite<F, G, T> {
return assign(
(...args: Parameters<T>) => createSuite<T, F, G>(suiteCallback)(...args),
(...args: Parameters<T>) => createSuite<F, G, T>(suiteCallback)(...args),
{
...getTypedMethods<F, G>(),
}
);
}

type StaticSuite<
T extends CB,
F extends TFieldName = string,
G extends TGroupName = string
G extends TGroupName = string,
T extends CB = CB
> = ((...args: Parameters<T>) => SuiteRunResult<F, G>) & TTypedMethods<F, G>;
2 changes: 1 addition & 1 deletion packages/vest/testUtils/TVestMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import * as vest from 'vest';
export type TVestMock = typeof vest;

export type TTestSuiteCallback = (...args: any[]) => void;
export type TTestSuite = vest.Suite<TTestSuiteCallback, TFieldName, TGroupName>;
export type TTestSuite = vest.Suite<TFieldName, TGroupName, TTestSuiteCallback>;
41 changes: 25 additions & 16 deletions website/docs/typescript_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ Vest is written fully in TypeScript, and as such, it provides extensive TypeScri

## Suite Generics

The Suite's `create` function takes three generic types - `Callback`, `FieldName`, `GroupName`.
The Suite's `create` function takes three **optional** generic types - `FieldName`, `GroupName` and `Callback`.

- `Callback`: The type for the suite callback. This type is propagated into the suite callback, and can be used to defined the shape of the data for the suite callback.
- `FieldName`: A union of the allowed field names in the suite. This type is propagated to all the suite and suite response methods.
- `GroupName`: A union of the allowed group names in the suite. This type is propagated to all the suite and suite response methods.
| Name | Type | Optional? | Default | Description |
| ----------- | ---------- | --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FieldName` | `string` | Yes | `string` | A union of the allowed field names in the suite. This type is propagated to all the suite and suite response methods. |
| `GroupName` | `string` | Yes | `string` | A union of the allowed group names in the suite. This type is propagated to all the suite and suite response methods. |
| `Callback` | `Function` | Yes | `Function` | The type for the suite callback. This type is propagated into the suite callback, and can be used to defined the shape of the data for the suite callback. |

```typescript
import { create } from 'vest';

type Callback = (data: {username: string, password: string}) => void;
type FieldName = "username" | "password";
type GroupName = "SignIn" | "ChangePassword";
type FieldName = 'username' | 'password';
type GroupName = 'SignIn' | 'ChangePassword';
type Callback = (data: { username: string; password: string }) => void;

const suite = create<Callback, FieldName, GroupName>((data) => { // data is now typed
const suite = create<FieldName, GroupName, Callback>(data => {
// data is now typed
// ...
});

Expand Down Expand Up @@ -71,18 +74,24 @@ To do so, you can type your suite as mentioned in the previous section, and dest
```typescript
import { create } from 'vest';

type TData = {username: string, password: string};
type Callback = (data: TData) => void;
type TData = { username: string; password: string };
type FieldName = keyof TData;
type GroupName = "SignIn" | "ChangePassword";
type GroupName = 'SignIn' | 'ChangePassword';
type Callback = (data: TData) => void;

const suite = create<Callback, FieldName, GroupName>((data) => {
const suite = create<FieldName, GroupName, Callback>(data => {
only('username');

test('username', 'Password is required' ,() => {/*...*/}); //
test('password', 'Password is too required' ,() => {/*...*/}); //
test('username', 'Password is required', () => {
/*...*/
}); //
test('password', 'Password is too required', () => {
/*...*/
}); //

test('confirm', 'Passwords do not match' ,() => {/*...*/}); // 🚨 Will throw a compilation error
test('confirm', 'Passwords do not match', () => {
/*...*/
}); // 🚨 Will throw a compilation error
});

const { test, group, only } = suite;
Expand All @@ -92,7 +101,7 @@ const { test, group, only } = suite;

Vest exports the following types so you can use them to annotate your functions and variables:

- `Suite<Callback, FieldName, GroupName>`<br/>
- `Suite<FieldName, GroupName, Callback>`<br/>
A single suite instance.

- `SuiteRunResult<FieldName, GroupName>`<br/>
Expand Down

2 comments on commit a59066f

@vercel
Copy link

@vercel vercel bot commented on a59066f May 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

vest – ./website

vest.vercel.app
vest-ealush.vercel.app
www.vestjs.dev
vestjs.dev
vest-git-latest-ealush.vercel.app

@vercel
Copy link

@vercel vercel bot commented on a59066f May 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

vest-next – ./website

vest-next-ealush.vercel.app
vest-website.vercel.app
vest-next-git-latest-ealush.vercel.app
vest-next.vercel.app

Please sign in to comment.