Skip to content

Commit 4876d2d

Browse files
authoredAug 17, 2024··
refactor(types): export infer utility types (#235)
Code in this PR adds and exports infer utility types for safe action client, middleware functions, safe actions and hooks. re #233
1 parent 9cb9b12 commit 4876d2d

File tree

7 files changed

+674
-13
lines changed

7 files changed

+674
-13
lines changed
 

‎packages/next-safe-action/src/hooks-utils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from "react";
22
import {} from "react/experimental";
33
import type {} from "zod";
44
import type { InferIn, Schema } from "./adapters/types";
5-
import type { HookActionStatus, HookBaseUtils, HookCallbacks, HookResult } from "./hooks.types";
5+
import type { HookActionStatus, HookBaseUtils, HookCallbacks, HookResult, HookShorthandStatus } from "./hooks.types";
66

77
export const getActionStatus = <
88
ServerError,
@@ -42,7 +42,7 @@ export const getActionShorthandStatusObject = ({
4242
}: {
4343
status: HookActionStatus;
4444
isTransitioning: boolean;
45-
}) => {
45+
}): HookShorthandStatus => {
4646
return {
4747
isIdle: status === "idle",
4848
isExecuting: status === "executing",

‎packages/next-safe-action/src/hooks.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ import {} from "react/experimental";
77
import type {} from "zod";
88
import type { InferIn, Schema } from "./adapters/types";
99
import { getActionShorthandStatusObject, getActionStatus, useActionCallbacks, useExecuteOnMount } from "./hooks-utils";
10-
import type { HookBaseUtils, HookCallbacks, HookResult, HookSafeActionFn } from "./hooks.types";
10+
import type {
11+
HookBaseUtils,
12+
HookCallbacks,
13+
HookResult,
14+
HookSafeActionFn,
15+
UseActionHookReturn,
16+
UseOptimisticActionHookReturn,
17+
} from "./hooks.types";
1118
import { isError } from "./utils";
1219

1320
// HOOKS
@@ -29,7 +36,7 @@ export const useAction = <
2936
>(
3037
safeActionFn: HookSafeActionFn<ServerError, S, BAS, CVE, CBAVE, Data>,
3138
utils?: HookBaseUtils<S> & HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
32-
) => {
39+
): UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> => {
3340
const [isTransitioning, startTransition] = React.useTransition();
3441
const [result, setResult] = React.useState<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
3542
const [clientInput, setClientInput] = React.useState<S extends Schema ? InferIn<S> : void>();
@@ -124,7 +131,7 @@ export const useAction = <
124131
return {
125132
execute,
126133
executeAsync,
127-
input: clientInput,
134+
input: clientInput as S extends Schema ? InferIn<S> : undefined,
128135
result,
129136
reset,
130137
status,
@@ -154,7 +161,7 @@ export const useOptimisticAction = <
154161
updateFn: (state: State, input: S extends Schema ? InferIn<S> : undefined) => State;
155162
} & HookBaseUtils<S> &
156163
HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
157-
) => {
164+
): UseOptimisticActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data, State> => {
158165
const [isTransitioning, startTransition] = React.useTransition();
159166
const [result, setResult] = React.useState<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
160167
const [clientInput, setClientInput] = React.useState<S extends Schema ? InferIn<S> : void>();
@@ -255,7 +262,7 @@ export const useOptimisticAction = <
255262
return {
256263
execute,
257264
executeAsync,
258-
input: clientInput,
265+
input: clientInput as S extends Schema ? InferIn<S> : undefined,
259266
result,
260267
optimisticState,
261268
reset,

‎packages/next-safe-action/src/hooks.types.ts

+108-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { InferIn, Schema } from "./adapters/types";
2-
import type { SafeActionResult } from "./index.types";
2+
import type { SafeActionFn, SafeActionResult, SafeStateActionFn } from "./index.types";
33
import type { MaybePromise, Prettify } from "./utils.types";
44

55
/**
@@ -83,6 +83,112 @@ export type HookSafeStateActionFn<
8383
) => Promise<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
8484

8585
/**
86-
* Type of the action status returned by `useAction` and `useOptimisticAction` hooks.
86+
* Type of the action status returned by `useAction`, `useOptimisticAction` and `useStateAction` hooks.
8787
*/
8888
export type HookActionStatus = "idle" | "executing" | "hasSucceeded" | "hasErrored";
89+
90+
/**
91+
* Type of the shorthand status object returned by `useAction`, `useOptimisticAction` and `useStateAction` hooks.
92+
*/
93+
export type HookShorthandStatus = {
94+
isIdle: boolean;
95+
isExecuting: boolean;
96+
isTransitioning: boolean;
97+
isPending: boolean;
98+
hasSucceeded: boolean;
99+
hasErrored: boolean;
100+
};
101+
102+
/**
103+
* Type of the return object of the `useAction` hook.
104+
*/
105+
export type UseActionHookReturn<
106+
ServerError,
107+
S extends Schema | undefined,
108+
BAS extends readonly Schema[],
109+
CVE,
110+
CBAVE,
111+
Data,
112+
> = {
113+
execute: (input: S extends Schema ? InferIn<S> : void) => void;
114+
executeAsync: (
115+
input: S extends Schema ? InferIn<S> : void
116+
) => Promise<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data> | undefined>;
117+
input: S extends Schema ? InferIn<S> : undefined;
118+
result: Prettify<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
119+
reset: () => void;
120+
status: HookActionStatus;
121+
} & HookShorthandStatus;
122+
123+
/**
124+
* Type of the return object of the `useOptimisticAction` hook.
125+
*/
126+
export type UseOptimisticActionHookReturn<
127+
ServerError,
128+
S extends Schema | undefined,
129+
BAS extends readonly Schema[],
130+
CVE,
131+
CBAVE,
132+
Data,
133+
State,
134+
> = UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> &
135+
HookShorthandStatus & {
136+
optimisticState: State;
137+
};
138+
139+
/**
140+
* Type of the return object of the `useStateAction` hook.
141+
*/
142+
export type UseStateActionHookReturn<
143+
ServerError,
144+
S extends Schema | undefined,
145+
BAS extends readonly Schema[],
146+
CVE,
147+
CBAVE,
148+
Data,
149+
> = Omit<UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>, "executeAsync" | "reset"> & HookShorthandStatus;
150+
151+
/**
152+
* Type of the return object of the `useAction` hook.
153+
*/
154+
export type InferUseActionHookReturn<T extends Function> =
155+
T extends SafeActionFn<
156+
infer ServerError,
157+
infer S extends Schema | undefined,
158+
infer BAS extends readonly Schema[],
159+
infer CVE,
160+
infer CBAVE,
161+
infer Data
162+
>
163+
? UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>
164+
: never;
165+
166+
/**
167+
* Type of the return object of the `useOptimisticAction` hook.
168+
*/
169+
export type InferUseOptimisticActionHookReturn<T extends Function, State = any> =
170+
T extends SafeActionFn<
171+
infer ServerError,
172+
infer S extends Schema | undefined,
173+
infer BAS extends readonly Schema[],
174+
infer CVE,
175+
infer CBAVE,
176+
infer Data
177+
>
178+
? UseOptimisticActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data, State>
179+
: never;
180+
181+
/**
182+
* Type of the return object of the `useStateAction` hook.
183+
*/
184+
export type InferUseStateActionHookReturn<T extends Function> =
185+
T extends SafeStateActionFn<
186+
infer ServerError,
187+
infer S extends Schema | undefined,
188+
infer BAS extends readonly Schema[],
189+
infer CVE,
190+
infer CBAVE,
191+
infer Data
192+
>
193+
? UseStateActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>
194+
: never;

‎packages/next-safe-action/src/index.types.ts

+80
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Infer, InferArray, InferIn, InferInArray, Schema, ValidationAdapter } from "./adapters/types";
2+
import type { SafeActionClient } from "./safe-action-client";
23
import type { MaybePromise, Prettify } from "./utils.types";
34
import type { BindArgsValidationErrors, ValidationErrors } from "./validation-errors.types";
45

@@ -201,3 +202,82 @@ export type SafeActionUtils<
201202
hasNotFound: boolean;
202203
}) => MaybePromise<void>;
203204
};
205+
206+
/**
207+
* Infer input types of a safe action.
208+
*/
209+
export type InferSafeActionFnInput<T extends Function> = T extends
210+
| SafeActionFn<any, infer S extends Schema | undefined, infer BAS extends readonly Schema[], any, any, any>
211+
| SafeStateActionFn<any, infer S extends Schema | undefined, infer BAS extends readonly Schema[], any, any, any>
212+
? S extends Schema
213+
? {
214+
clientInput: InferIn<S>;
215+
bindArgsClientInputs: InferInArray<BAS>;
216+
parsedInput: Infer<S>;
217+
bindArgsParsedInputs: InferArray<BAS>;
218+
}
219+
: {
220+
clientInput: undefined;
221+
bindArgsClientInputs: InferInArray<BAS>;
222+
parsedInput: undefined;
223+
bindArgsParsedInputs: InferArray<BAS>;
224+
}
225+
: never;
226+
227+
/**
228+
* Infer the result type of a safe action.
229+
*/
230+
export type InferSafeActionFnResult<T extends Function> = T extends
231+
| SafeActionFn<
232+
infer ServerError,
233+
infer S extends Schema | undefined,
234+
infer BAS extends readonly Schema[],
235+
infer CVE,
236+
infer CBAVE,
237+
infer Data
238+
>
239+
| SafeStateActionFn<
240+
infer ServerError,
241+
infer S extends Schema | undefined,
242+
infer BAS extends readonly Schema[],
243+
infer CVE,
244+
infer CBAVE,
245+
infer Data
246+
>
247+
? SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>
248+
: never;
249+
250+
/**
251+
* Infer the next context type returned by a middleware function using the `next` function.
252+
*/
253+
export type InferMiddlewareFnNextCtx<T> =
254+
T extends MiddlewareFn<any, any, any, infer NextCtx extends object> ? NextCtx : never;
255+
256+
/**
257+
* Infer the context type of a safe action client or middleware function.
258+
*/
259+
export type InferCtx<T> = T extends
260+
| SafeActionClient<any, any, any, any, infer Ctx extends object, any, any, any, any, any>
261+
| MiddlewareFn<any, any, infer Ctx extends object, any>
262+
? Ctx
263+
: never;
264+
265+
/**
266+
* Infer the metadata type of a safe action client or middleware function.
267+
*/
268+
export type InferMetadata<T> = T extends
269+
| SafeActionClient<any, any, any, infer MD, any, any, any, any, any, any>
270+
| MiddlewareFn<any, infer MD, any, any>
271+
? MD
272+
: never;
273+
274+
/**
275+
* Infer the server error type from a safe action client or a middleware function or a safe action function.
276+
*/
277+
export type InferServerError<T> = T extends
278+
| SafeActionClient<infer ServerError, any, any, any, any, any, any, any, any, any>
279+
| MiddlewareFn<infer ServerError, any, any, any>
280+
| SafeActionFn<infer ServerError, any, any, any, any, any>
281+
| SafeStateActionFn<infer ServerError, any, any, any, any, any>
282+
? ServerError
283+
: never;

‎packages/next-safe-action/src/stateful-hooks.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {} from "react/experimental";
55
import type {} from "zod";
66
import type { InferIn, Schema } from "./adapters/types";
77
import { getActionShorthandStatusObject, getActionStatus, useActionCallbacks, useExecuteOnMount } from "./hooks-utils";
8-
import type { HookBaseUtils, HookCallbacks, HookSafeStateActionFn } from "./hooks.types";
8+
import type { HookBaseUtils, HookCallbacks, HookSafeStateActionFn, UseStateActionHookReturn } from "./hooks.types";
99
/**
1010
* Use the stateful action from a Client Component via hook. Used for actions defined with [`stateAction`](https://next-safe-action.dev/docs/safe-action-client/instance-methods#action--stateaction).
1111
* @param safeActionFn The action function
@@ -27,7 +27,7 @@ export const useStateAction = <
2727
permalink?: string;
2828
} & HookBaseUtils<S> &
2929
HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
30-
) => {
30+
): UseStateActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> => {
3131
const [result, dispatcher, isExecuting] = React.useActionState(
3232
safeActionFn,
3333
utils?.initResult ?? {},
@@ -75,7 +75,7 @@ export const useStateAction = <
7575

7676
return {
7777
execute,
78-
input: clientInput,
78+
input: clientInput as S extends Schema ? InferIn<S> : undefined,
7979
result,
8080
status,
8181
...getActionShorthandStatusObject({ status, isTransitioning }),

‎website/docs/types.md ‎website/docs/types/index.md

+225-1
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,103 @@ export type HandleBindArgsValidationErrorsShapeFn<BAS extends readonly Schema[],
308308
) => FBAVE;
309309
```
310310
311+
### `InferSafeActionFnInput`
312+
313+
Infer input types of a safe action.
314+
315+
```typescript
316+
export type InferSafeActionFnInput<T extends Function> = T extends
317+
| SafeActionFn<any, infer S extends Schema | undefined, infer BAS extends readonly Schema[], any, any, any>
318+
| SafeStateActionFn<any, infer S extends Schema | undefined, infer BAS extends readonly Schema[], any, any, any>
319+
? S extends Schema
320+
? {
321+
clientInput: InferIn<S>;
322+
bindArgsClientInputs: InferInArray<BAS>;
323+
parsedInput: Infer<S>;
324+
bindArgsParsedInputs: InferArray<BAS>;
325+
}
326+
: {
327+
clientInput: undefined;
328+
bindArgsClientInputs: InferInArray<BAS>;
329+
parsedInput: undefined;
330+
bindArgsParsedInputs: InferArray<BAS>;
331+
}
332+
: never;
333+
```
334+
335+
### `InferSafeActionFnResult`
336+
337+
Infer the result type of a safe action.
338+
339+
```typescript
340+
export type InferSafeActionFnResult<T extends Function> = T extends
341+
| SafeActionFn<
342+
infer ServerError,
343+
infer S extends Schema | undefined,
344+
infer BAS extends readonly Schema[],
345+
infer CVE,
346+
infer CBAVE,
347+
infer Data
348+
>
349+
| SafeStateActionFn<
350+
infer ServerError,
351+
infer S extends Schema | undefined,
352+
infer BAS extends readonly Schema[],
353+
infer CVE,
354+
infer CBAVE,
355+
infer Data
356+
>
357+
? SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>
358+
: never;
359+
```
360+
361+
### `InferMiddlewareFnNextCtx`
362+
363+
Infer the next context type returned by a middleware function using the `next` function.
364+
365+
```typescript
366+
export type InferMiddlewareFnNextCtx<T> =
367+
T extends MiddlewareFn<any, any, any, infer NextCtx extends object> ? NextCtx : never;
368+
```
369+
370+
### `InferCtx`
371+
372+
Infer the context type of a safe action client or middleware function.
373+
374+
```typescript
375+
export type InferCtx<T> = T extends
376+
| SafeActionClient<any, any, any, any, infer Ctx extends object, any, any, any, any, any>
377+
| MiddlewareFn<any, any, infer Ctx extends object, any>
378+
? Ctx
379+
: never;
380+
```
381+
382+
### `InferMetadata`
383+
384+
Infer the metadata type of a safe action client or middleware function.
385+
386+
```typescript
387+
export type InferMetadata<T> = T extends
388+
| SafeActionClient<any, any, any, infer MD, any, any, any, any, any, any>
389+
| MiddlewareFn<any, infer MD, any, any>
390+
? MD
391+
: never;
392+
```
393+
394+
### `InferServerError`
395+
396+
Infer the server error type from a safe action client or a middleware function or a safe action function.
397+
398+
```typescript
399+
export type InferServerError<T> = T extends
400+
| SafeActionClient<infer ServerError, any, any, any, any, any, any, any, any, any>
401+
| MiddlewareFn<infer ServerError, any, any, any>
402+
| SafeActionFn<infer ServerError, any, any, any, any, any>
403+
| SafeStateActionFn<infer ServerError, any, any, any, any, any>
404+
? ServerError
405+
: never;
406+
```
407+
311408
## /hooks
312409
313410
### `HookBaseUtils`
@@ -406,12 +503,139 @@ export type HookSafeStateActionFn<
406503
407504
### `HookActionStatus`
408505
409-
Type of the action status returned by `useAction` and `useOptimisticAction` hooks.
506+
Type of the action status returned by `useAction`, `useOptimisticAction` and `useStateAction` hooks.
410507
411508
```typescript
412509
type HookActionStatus = "idle" | "executing" | "hasSucceeded" | "hasErrored";
413510
```
414511
512+
### `HookShorthandStatus`
513+
514+
Type of the shorthand status object returned by `useAction`, `useOptimisticAction` and `useStateAction` hooks.
515+
516+
```typescript
517+
export type HookShorthandStatus = {
518+
isIdle: boolean;
519+
isExecuting: boolean;
520+
isTransitioning: boolean;
521+
isPending: boolean;
522+
hasSucceeded: boolean;
523+
hasErrored: boolean;
524+
};
525+
```
526+
527+
### `UseActionHookReturn`
528+
529+
Type of the return object of the `useAction` hook.
530+
531+
```typescript
532+
export type UseActionHookReturn<
533+
ServerError,
534+
S extends Schema | undefined,
535+
BAS extends readonly Schema[],
536+
CVE,
537+
CBAVE,
538+
Data,
539+
> = {
540+
execute: (input: S extends Schema ? InferIn<S> : void) => void;
541+
executeAsync: (
542+
input: S extends Schema ? InferIn<S> : void
543+
) => Promise<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data> | undefined>;
544+
input: S extends Schema ? InferIn<S> : undefined;
545+
result: Prettify<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
546+
reset: () => void;
547+
status: HookActionStatus;
548+
} & HookShorthandStatus;
549+
```
550+
551+
### `UseOptimisticActionHookReturn`
552+
553+
Type of the return object of the `useOptimisticAction` hook.
554+
555+
```typescript
556+
export type UseOptimisticActionHookReturn<
557+
ServerError,
558+
S extends Schema | undefined,
559+
BAS extends readonly Schema[],
560+
CVE,
561+
CBAVE,
562+
Data,
563+
State,
564+
> = UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> &
565+
HookShorthandStatus & {
566+
optimisticState: State;
567+
};
568+
```
569+
570+
### `UseStateActionHookReturn`
571+
572+
Type of the return object of the `useStateAction` hook.
573+
574+
```typescript
575+
export type UseStateActionHookReturn<
576+
ServerError,
577+
S extends Schema | undefined,
578+
BAS extends readonly Schema[],
579+
CVE,
580+
CBAVE,
581+
Data,
582+
> = Omit<UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>, "executeAsync" | "reset"> & HookShorthandStatus;
583+
```
584+
585+
### `InferUseActionHookReturn`
586+
587+
Type of the return object of the `useAction` hook.
588+
589+
```typescript
590+
export type InferUseActionHookReturn<T extends Function> =
591+
T extends SafeActionFn<
592+
infer ServerError,
593+
infer S extends Schema | undefined,
594+
infer BAS extends readonly Schema[],
595+
infer CVE,
596+
infer CBAVE,
597+
infer Data
598+
>
599+
? UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>
600+
: never;
601+
```
602+
603+
### `InferUseOptimisticActionHookReturn`
604+
605+
Type of the return object of the `useOptimisticAction` hook.
606+
607+
```typescript
608+
export type InferUseOptimisticActionHookReturn<T extends Function, State = any> =
609+
T extends SafeActionFn<
610+
infer ServerError,
611+
infer S extends Schema | undefined,
612+
infer BAS extends readonly Schema[],
613+
infer CVE,
614+
infer CBAVE,
615+
infer Data
616+
>
617+
? UseOptimisticActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data, State>
618+
: never;
619+
```
620+
621+
### `InferUseStateActionHookReturn`
622+
623+
Type of the return object of the `useStateAction` hook.
624+
625+
```typescript
626+
export type InferUseStateActionHookReturn<T extends Function> =
627+
T extends SafeStateActionFn<
628+
infer ServerError,
629+
infer S extends Schema | undefined,
630+
infer BAS extends readonly Schema[],
631+
infer CVE,
632+
infer CBAVE,
633+
infer Data
634+
>
635+
? UseStateActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>
636+
: never;
637+
```
638+
415639
---
416640
417641
## Internal utility types

‎website/docs/types/infer-types.md

+244
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
---
2+
sidebar_position: 1
3+
description: Learn how to infer types with next-safe-action.
4+
---
5+
6+
# Infer types
7+
8+
next-safe-action, since version 7.6.4, exports utility types for type inference. Here's a guide on how to use them.
9+
10+
Suppose we have declared this safe action client:
11+
12+
```typescript title="src/lib/safe-action.ts"
13+
import { z } from "zod";
14+
import { createSafeActionClient, experimental_createMiddleware } from "next-safe-action";
15+
import { getSessionData } from "@/services/auth"
16+
17+
// Here we declare a standalone auth middleware.
18+
export const authMiddleware = experimental_createMiddleware<{
19+
ctx: { sessionToken: string };
20+
metadata: { actionName: string };
21+
}>().define(async ({ ctx, next }) => {
22+
const { sessionId, userId } = await getSessionData(ctx.sessionToken);
23+
24+
return next({
25+
ctx: {
26+
sessionId,
27+
userId,
28+
},
29+
});
30+
});
31+
32+
// Here we declare the safe action client.
33+
export const actionClient = createSafeActionClient({
34+
defineMetadataSchema: () => {
35+
return z.object({
36+
actionName: z.string(),
37+
});
38+
},
39+
handleReturnedServerError: (e) => {
40+
return {
41+
errorMessage: e.message,
42+
};
43+
},
44+
})
45+
.use(async ({ next }) => {
46+
return next({
47+
ctx: {
48+
sessionToken: "someToken",
49+
},
50+
});
51+
})
52+
.use(authMiddleware);
53+
```
54+
55+
And then this action function:
56+
57+
```typescript title="src/app/test-action.ts"
58+
"use server";
59+
60+
import { z } from "zod";
61+
import { actionClient } from "@/lib/safe-action";
62+
63+
const testActionSchema = z.object({
64+
username: z.string(),
65+
});
66+
67+
const testActionBindArgsSchemas: [email: z.ZodString, age: z.ZodNumber] = [z.string(), z.number()];
68+
69+
export const testAction = actionClient
70+
.use(authMiddleware)
71+
.schema(testActionSchema)
72+
.bindArgsSchemas(testActionBindArgsSchemas)
73+
.action(async () => {
74+
return {
75+
successful: true,
76+
};
77+
});
78+
```
79+
80+
We'll use these exported functions in the following examples.
81+
82+
## `/`
83+
84+
The library exports several utility types from the root path that help you infer types of a safe action client, a middleware function or a safe action function.
85+
86+
Here's the list of utility types exported from `next-safe-action` path:
87+
- `InferSafeActionFnInput`: infer input types of a safe action function
88+
- `InferSafeActionFnResult`: infer result type of a safe action function
89+
- `InferMiddlewareFnNextCtx`: infer the type of context returned by a middleware function using the `next` function
90+
- `InferCtx`: infer the type of context of a safe action client, or the context passed to a middleware function
91+
- `InferMetadata`: infer the type of metadata of a safe action client or middleware function
92+
- `InferServerError`: infer the type of the `serverError` of a safe action function, middleware function or safe action function
93+
94+
### Example
95+
96+
```typescript
97+
import type {
98+
InferCtx,
99+
InferMetadata,
100+
InferMiddlewareFnNextCtx,
101+
InferSafeActionFnInput,
102+
InferSafeActionFnResult,
103+
InferServerError,
104+
} from "next-safe-action";
105+
import type { actionClient, authMiddleware } from "@/lib/safe-action";
106+
import type { testAction } from "@/app/test-action";
107+
108+
// Use `InferSafeActionFnInput` to infer the input types of a safe action function.
109+
type inferredTestActionInput = InferSafeActionFnInput<typeof testAction>;
110+
/*
111+
{
112+
clientInput: {
113+
username: string;
114+
};
115+
bindArgsClientInputs: [email: string, age: number];
116+
parsedInput: {
117+
username: string;
118+
};
119+
bindArgsParsedInputs: [email: string, age: number];
120+
}
121+
*/
122+
123+
// Use `InferSafeActionFnResult` to infer the result type of a safe action function.
124+
type inferredTestActionResult = InferSafeActionFnResult<typeof testAction>;
125+
/*
126+
{
127+
data?: {
128+
successful: boolean;
129+
} | undefined;
130+
serverError?: string | undefined;
131+
validationErrors?: {
132+
_errors?: string[];
133+
username?: {
134+
_errors?: string[];
135+
} | undefined;
136+
} | undefined;
137+
bindArgsValidationErrors?: [email: { _errors?: string[] }, age: { _errors?: string[] }] | undefined;
138+
}
139+
*/
140+
141+
// Use `InferMiddlewareFnNextCtx` to infer the type of the context returned by a middleware function using
142+
// the `next` function.
143+
type inferredAuthMiddlewareNextCtx = InferMiddlewareFnNextCtx<typeof authMiddleware>;
144+
/*
145+
{
146+
sessionId: string;
147+
userId: string;
148+
}
149+
*/
150+
151+
// Use `InferCtx` to infer the type of the context of a safe action client, or the context passed to a
152+
// middleware function. Here's an example with a safe action client:
153+
type inferredSafeActionClientCtx = InferCtx<typeof actionClient>;
154+
/*
155+
{
156+
sessionToken: string;
157+
} & {
158+
sessionId: string;
159+
userId: string;
160+
}
161+
*/
162+
163+
// Use `InferMetadata` to infer the type of the metadata of a safe action client or middleware function.
164+
// Here's an example with a middleware function:
165+
type inferredMiddlewareMetadata = InferMetadata<typeof authMiddleware>;
166+
/*
167+
{
168+
actionName: string;
169+
}
170+
*/
171+
172+
// Use `InferServerError` to infer the type of the `serverError` of a safe action client, middleware function,
173+
// or safe action function. Here's an example with a safe action:
174+
type inferredServerError = InferServerError<typeof testAction>;
175+
/*
176+
{
177+
errorMessage: string;
178+
}
179+
*/
180+
```
181+
182+
## `/hooks`
183+
184+
The library also exports three types from the `/hooks` path that help you infer types when using `useAction`, `useOptimisticAction` and `useStateAction` hooks.
185+
186+
Here's a list of utility types exported from `next-safe-action/hooks`:
187+
188+
- `InferUseActionHookReturn`: infers the return type of the `useAction` hook - only works with actions defined using the [`action`](/docs/safe-action-client/instance-methods#action--stateaction) method
189+
- `InferUseOptimisticActionHookReturn`: infers the return type of the `useOptimisticAction` hook - only works with stateless actions defined using the [`action`](/docs/safe-action-client/instance-methods#action--stateaction) method
190+
- `InferUseStateActionHookReturn`: infers the return type of the `useStateAction` hook - only works with stateful actions defined using the [`stateAction`](/docs/safe-action-client/instance-methods#action--stateaction) method
191+
192+
### Example
193+
194+
```typescript
195+
import type { testAction } from "@/app/test-action";
196+
197+
// Use `InferUseActionHookReturn` to infer the return type of the `useAction` hook with a provided
198+
// safe action function.
199+
type inferredTestActionHookReturn = InferUseActionHookReturn<typeof testAction>;
200+
/*
201+
{
202+
execute: (input: { username: string }) => void;
203+
executeAsync: (input: { username: string }) => Promise<SafeActionResult>;
204+
input: { username: string };
205+
result: SafeActionResult;
206+
reset: () => void;
207+
status: HookActionStatus;
208+
} & HookShorthandStatus
209+
*/
210+
211+
// Use `InferUseActionHookReturn` to infer the return type of the `useOptimisticAction` hook with a provided
212+
// safe action function. You can pass the server state as the second generic parameter, which defaults
213+
// to `any`.
214+
type inferredTestActionOptimisticHookReturn = InferUseOptimisticActionHookReturn<
215+
typeof testAction,
216+
{ myServerState: { foo: string } }
217+
>;
218+
/*
219+
{
220+
execute: (input: { username: string }) => void;
221+
executeAsync: (input: { username: string }) => Promise<SafeActionResult>;
222+
input: { username: string };
223+
result: SafeActionResult;
224+
reset: () => void;
225+
status: HookActionStatus;
226+
optimisticState: { myServerState: { foo: string } };
227+
} & HookShorthandStatus
228+
*/
229+
230+
// Use `InferUseStateActionHookReturn` to infer the return type of the `useStateAction` hook with a
231+
// provided stateful safe action. In this case, by providing the type of `testAction` as the
232+
// generic parameter will, the resulting type will be `never`, because `testAction` is not defined
233+
// using `stateAction()` method. Supposing that we change the definition of the function to be stateful,
234+
// the resulting type will be:
235+
type inferredTestActionStateHookReturn = InferUseStateActionHookReturn<typeof testAction>;
236+
/*
237+
{
238+
execute: (input: { username: string }) => void;
239+
input: { username: string };
240+
result: SafeActionResult;
241+
status: HookActionStatus;
242+
} & HookShorthandStatus
243+
*/
244+
```

0 commit comments

Comments
 (0)
Please sign in to comment.