2

I'm starting my journey with ts and looking into TypeGraphQL right now. I've noticed something I don't understand and haven't seen before:

export declare type ReturnTypeFunc = (returns?: void) => ReturnTypeFuncValue;

How should that type be interpreted? What does this (returns?: void) represent?

2
  • 1
    I think it's to prevent you from calling it with parameters. ? means it's optional, so you can omit it, but it has a void type meaning if you do pass it there's nothing you can pass that works Commented Dec 14, 2022 at 22:16
  • 1
    void can only be undefined, or null if strictNullChecks is not specified. As for the intent of it, you'd have to ask the project authors. If it's not documented explicitly already, then it probably isn't relevant to consumers of the project. Commented Dec 14, 2022 at 22:20

2 Answers 2

2

The type ReturnTypeFunc is used in the Query decorator:

export declare function Query(returnTypeFunc: ReturnTypeFunc, options?: AdvancedOptions): MethodDecorator;

This is how Query decorator is usually used:

  @Query(returns => [SampleObject])

As far as I remember, the parameter returns is added to help with the readability: This query returns an array of SampleObject. If you remove the returns argument in type ReturnTypeFunc, you cannot do this anymore, and you have to write @Query(() => [SampleObject]) instead.

Some other decorators that have an optional void argument are:

@Resolver(of => Recipe) // This is a resolver for Recipe. See type ClassTypeResolver

@Field(type => [Rate]) // This field is of type Rate. See type ClassTypeResolver.

Edit:

  1. As mentioned in the comments, you can only assign null (if strictNullChecks is not specified) or undefined to a variable of type void.
  2. The mentioned decorators annotate classes. The graphql schema is generated by using the provided metadata to the decorators. To the best of my knowledge, you are not supposed to define a function that is of type ReturnTypeFunc. The only reason those parameters are of type void, is to improve readability of code.
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer @c0m1t. While I agree that it can improve readability, it's only valid if you understand the syntax and why this construct is/can be used syntactically. My question was more about a broader use-case for such a declaration.
1

The function signature you described is here, and its usage of the optional parameter of type void could be written for a number of reasons.

One reason is as a means of preventing callers from providing an argument in normal circumstances, but to allow for internal library code to make use of undocumented, internal logic that might depend on functional use of the value.

Here's a very contrived example that demonstrates what I described above:

TS Playground

function fn (param?: void): void {
  if ((param as any) === 'log a special message') {
    console.log('Internal behavior matched');
  }
};

fn(); // Ok
fn('hello'); // Not ok

/**
 * Written as returning void, but actually returns
 * something that is used for internal library behavior
 */
function internalFnForInteralThings (): void {
  return 'log a special message' as any;
};

fn(internalFnForInteralThings()); // Ok (and logs "Internal behavior matched")

Ultimately, you'd have to examine the whole codebase of the project that exports the type to see how it is used in each case, and then using that knowledge, you could infer why the author chose to write the signature that way.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.