0

I'm converting a JS project to TS and here I have this error (using urql):

A function whose declared type is neither 'void' nor 'any' must return a value. ts(2355) on line:

playerCreate: (result, args, cache): UpdateResolver => {

Why?

const updates = {
  Mutation: {
    playerCreate: (result, args, cache): UpdateResolver => {
      const playersQueries = cache
        .inspectFields("Query")
        .filter((x) => x.fieldName === "players");
      playersQueries.forEach(({ fieldName, arguments: variables }) =>
        cache.invalidate("Query", fieldName, variables)
      );
    },

    playerDelete: (result, args, cache, info): UpdateResolver => {
      // using result, args, cache here
    },
  },
};

I can see Updateresolver is declared like this:

export declare type UpdateResolver = (result: Data, args: Variables, cache: Cache, info: ResolveInfo) => void;

UPDATE:

Someone rightly told me that I'm saying that this function returns an UpdateResolver while the type is for the function not the return-type.

Hence the question:

How can I correctly type here playerCreate and playerDelete?

8
  • Figure out what you want to return (in the JS logic) in the playerCreate method, then return it, and then change the UpdateResolver type to match it. It's not clear what JS logic you want there. Commented Mar 18, 2021 at 14:55
  • TS doesn't know about result, args, cache, info. I wanna tell it: "that function type is UpdateResolver!". Only I don't know how... Commented Mar 18, 2021 at 14:56
  • 1
    Does this answer your question? Type definition in object literal in TypeScript Commented Mar 18, 2021 at 15:12
  • 1
    @FredHors it's a property with an arrow function assigned to it, not really a method. { foo: "hello" } and { bar: () => {} } are syntactically equivalent: an object with a property where you assign a value to the property. The duplicate shows how you can give such a thing a type - either type the object or do a type assertion. The latter is is the same as the answer you already got. Commented Mar 18, 2021 at 15:46
  • 2
    @FredHors what @VLAZ is saying regarding typing the object would be to write const updates: {Mutation: Record<string, UpdateResolver>} = {... and remove the types from the individual functions. You can also write the functions outside of the object and piece it together. const playerCreate: UpdateResolver = (.... then const updates = { Mutation: { playerCreate, playerDelete }, }, }; The problem is that you can't set a property and declare the type for that property at the same time without using as assertion (which can be dangerous since it is an override, not a check). Commented Mar 19, 2021 at 1:50

1 Answer 1

3

Try to change the code to this:

const updates = {
  Mutation: {
    playerCreate: (result: Data, args: Variables, cache: Cache): void => {
      const playersQueries = cache
        .inspectFields("Query")
        .filter((x) => x.fieldName === "players");
      playersQueries.forEach(({ fieldName, arguments: variables }) =>
        cache.invalidate("Query", fieldName, variables)
      );
    },

    playerDelete: (result: Data, args: Variables, cache: Cache, info: ResolveInfo): void => {
      // using result, args, cache here
    },
  },
};

EDIT: I've found out that it is actually possible by using the as operator:

const updates = {
  Mutation: {
    playerCreate: (((result, args, cache) => {
      const playersQueries = cache
        .inspectFields("Query")
        .filter((x) => x.fieldName === "players");
      playersQueries.forEach(({ fieldName, arguments: variables }) =>
        cache.invalidate("Query", fieldName, variables)
      );
    }) as UpdateResolver),

    playerDelete: (((result, args, cache, info) => {
      // using result, args, cache here
    }) as UpdateResolver),
  },
};

What is the as operator in TypeScript?

It tells the TypeScript compiler to think that the expression before the operator has the type after the operator. You can do some weird things with it:

const test = "some string" as number;
// "test" is number here!!

So be careful where you use it! When you apply it to functions, TypeScript will see that e. g. parameter one should have type T, so it pretends, that the function also takes a parameter of type T.

There is an alternative to as, but it cannot be used in TSX files:

const something = <number>"hello";
// don't do that if you don't know the actual type!

Of course this example is wrong, because TypeScript will think that the string is a number, but it isn't. But it shows the usage of the type assertion.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, this is what I wanna avoid: result: Data, args: Variables, cache: Cache): void because I can use UpdateResolver type.
I'm sorry, but it is not possible. You cannot type a function after creating it.
"But it shows the usage of the type cast." it shows type assertion. Type casting is different and not what as (or the <> syntax) do. Type casting is when you take a value at runtime and change its type at runtime. Since TS only operates at compile time, there is no type casting possible. In Java, for example, you can do a cast of float to integer (int) 3.14 which will give you 3 .

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.