Skip to content

Commit

Permalink
Try to remove duplication in operations
Browse files Browse the repository at this point in the history
  • Loading branch information
sodic committed Jul 11, 2024
1 parent d2454b0 commit a9f6f44
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 25 deletions.
18 changes: 13 additions & 5 deletions waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
_Awaited,
_ReturnType,
} from "wasp/universal/types"
import { Expand } from "../../universal/types";

// PRIVATE API (for SDK, should maybe be public, users define values of this
// type).
Expand Down Expand Up @@ -77,16 +78,23 @@ export type GenericOperationRpc = (args: never) => Promise<unknown>

// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/2170#issue-2398830273
type ClientOperation<Input, Output> =
IfAny<
Expand<IfAny<
Input,
(args?: any) => Promise<Output>,
ClientOperationWithOptionalArgs<any, Output>,
ClientOperationWithNonAnyInput<Input, Output>
>
>>

// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471
type ClientOperationWithNonAnyInput<Input, Output> =
[Input] extends [never]
? (args?: unknown) => Promise<Output>
? ClientOperationWithOptionalArgs<unknown, Output>
: [Input] extends [void]
? () => Promise<Output>
: (args: Input) => Promise<Output>
: ClientOperationWithMandatoryArgs<Input, Output>

type ClientOperationWithMandatoryArgs<Input, Output> =
(args: Input) => Promise<Output>

type ClientOperationWithOptionalArgs<Input, Output> =
(args?: Input) => Promise<Output>

Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{{={= =}=}}
import { IfAny, _Awaited, _ReturnType } from '../../universal/types'
import {
IfAny,
_Awaited,
_ReturnType,
Expand
} from '../../universal/types'

{=# isAuthEnabled =}
import { type AuthUser } from 'wasp/auth'
Expand Down Expand Up @@ -168,18 +173,21 @@ type AuthenticatedOperationArgsFor<Op extends GenericAuthenticatedOperationDefin
* @template Output The type of the operation's return value.
*/
type AuthenticatedOperation<Input, Output> =
IfAny<
Expand<IfAny<
Input,
(args: any, context: { user: AuthUser }) => Promise<Output>,
AuthenticatedOperationWithArgs<any, Output>,
AuthenticatedOperationWithNonAnyInput<Input, Output>
>
>>

type AuthenticatedOperationWithNonAnyInput<Input, Output> =
[Input] extends [never]
? (args: unknown, context: { user: AuthUser }) => Promise<Output>
? AuthenticatedOperationWithArgs<unknown, Output>
: [Input] extends [void]
? (context: { user: AuthUser }) => Promise<Output>
: (args: Input, context: { user: AuthUser }) => Promise<Output>
: AuthenticatedOperationWithArgs<Input, Output>

type AuthenticatedOperationWithArgs<Input, Output> =
(args: Input, context: { user: AuthUser }) => Promise<Output>

/**
* The principal type for an authenticated operation's definition (i.e., all
Expand All @@ -203,19 +211,25 @@ type GenericAuthenticatedOperationDefinition = AuthenticatedOperationDefinition<
* @template Output The type of the operation's return value.
*/
type UnauthenticatedOperation<Input, Output> =
IfAny<
Expand<IfAny<
Input,
(args: any) => Promise<Output>,
UnauthenticatedOperationWithOptionalArgs<any, Output>,
UnauthenticatedOperationWithNonAnyInput<Input, Output>
>
>>

// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471
type UnauthenticatedOperationWithNonAnyInput<Input, Output> =
[Input] extends [never]
? (args: unknown) => Promise<Output>
? UnauthenticatedOperationWithOptionalArgs<unknown, Output>
: [Input] extends [void]
? () => Promise<Output>
: (args: Input) => Promise<Output>
: UnauthenticatedOperationWithMandatoryArgs<Input, Output>

type UnauthenticatedOperationWithMandatoryArgs<Input, Output> =
(args: Input) => Promise<Output>

type UnauthenticatedOperationWithOptionalArgs<Input, Output> =
(args?: Input) => Promise<Output>

/**
* The principal type for an unauthenticated operation's definition (i.e., all
Expand Down
23 changes: 18 additions & 5 deletions waspc/data/Generator/templates/sdk/wasp/universal/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
// This is a helper type used exclusively for DX purposes. It's a No-op for the
// compiler, but expands the type's representatoin in IDEs (i.e., inlines all
// type constructors) to make it more readable for the user.
//
// It expands this SO answer to functions: https://stackoverflow.com/a/57683652
/**
* This is a helper type used exclusively for DX purposes. It's a No-op for the
* compiler, but expands the type's representatoin in IDEs (i.e., inlines all
* type constructors) to make it more readable for the user.
*
* It expands this SO answer to functions: https://stackoverflow.com/a/57683652
* Caveat: when used on functions that also have properties, the resulting type
* will lose those properties.
*/
export type Expand<T> = T extends (...args: infer A) => infer R
? (...args: A) => R
: T extends infer O
? { [K in keyof O]: O[K] }
: never

export type ExpandCallSignature<T> = ExpandIfFunction<T> & ExpandIfObject<T>

type ExpandIfObject<O> = O extends object ? { [K in keyof O]: O[K] } : O;

type ExpandIfFunction<F> =
F extends (...args: infer Args) => infer Ret
? (...args: Args) => Ret
: F

// TypeScript's native Awaited type exhibits strange behavior in VS Code (see
// https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159687537 for
// details). Until it's fixed, we're using our own type for this.
Expand Down
2 changes: 2 additions & 0 deletions waspc/examples/todoApp/src/testTypes/operations/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
getAnyAuth,
getAnyNoAuth,
getAnyToNumberSpecified,
getTask,
} from 'wasp/client/operations'

import {
Expand Down Expand Up @@ -66,4 +67,5 @@ type TestCases = [
Expect<Equal<typeof getAnyAuth, QueryMetadata & ((args?: any) => Promise<any>)>>,
Expect<Equal<typeof getAnyToNumberSpecified, QueryMetadata & ((args?: any) => Promise<number>)>>,
Expect<Equal<typeof getMe, QueryMetadata & (() => Promise<AuthUser | null>)>>,
Expect<Equal<typeof getTask, QueryMetadata & ((args: Pick<Task, 'id'>) => Promise<Task>)>>,
]
21 changes: 17 additions & 4 deletions waspc/examples/todoApp/src/testTypes/operations/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,27 @@ type TestCases = [
(payload: boolean, ctx: { user: AuthUser }) => Promise<void>
>
>,
// I need a test for this but without auth
Expect<
Equal<
typeof getAnything,
(args: unknown, ctx: { user: AuthUser }) => Promise<Payload>
>
>,
Expect<Equal<typeof getTrueVoid, (ctx: { user: AuthUser }) => Promise<string>>>,
Expect<Equal<typeof getAnyNoAuth, (args: any) => Promise<any>>>,
Expect<Equal<typeof getAnyAuth, (args: any, ctx: { user: AuthUser }) => Promise<any>>>,
Expect<Equal<typeof getAnyToNumberSpecified, (args: any, ctx: { user: AuthUser }) => Promise<number>>>,
Expect<
Equal<typeof getTrueVoid, (ctx: { user: AuthUser }) => Promise<string>>
>,
Expect<Equal<typeof getAnyNoAuth, (args?: any) => Promise<any>>>,
Expect<
Equal<
typeof getAnyAuth,
(args: any, ctx: { user: AuthUser }) => Promise<any>
>
>,
Expect<
Equal<
typeof getAnyToNumberSpecified,
(args: any, ctx: { user: AuthUser }) => Promise<number>
>
>
]

0 comments on commit a9f6f44

Please sign in to comment.