0

I have this code:

const baseUpstreamImpl = (
  client: IClient,
): ProtocolExtension<
  {
    foobar: (buff: Buffer) => Promise<string>;
  }
> => ({
  name: 'base upstream impl',
  type: 'upstream',
  messageCreators: {
    foobar: (buff: Buffer)  =>
      Promise.resolve({
        type: 'foobar',
        payload: buff,
      }),
  },
});

This . is the error I get for the foobar function:

[ts]
Type '(buff: Buffer) => Promise<{ type: string; payload: Buffer; }>' is not assignable to type '(...args: any[]) => Promise<IMessage<{ foobar: (buff: Buffer) => Promise<string>; }, "foobar">>'.
  Type 'Promise<{ type: string; payload: Buffer; }>' is not assignable to type 'Promise<IMessage<{ foobar: (buff: Buffer) => Promise<string>; }, "foobar">>'.
    Type '{ type: string; payload: Buffer; }' is not assignable to type 'IMessage<{ foobar: (buff: Buffer) => Promise<string>; }, "foobar">'.
      Types of property 'type' are incompatible.
        Type 'string' is not assignable to type '"foobar"'.
baseUpstreamImpl.ts(11, 5): The expected type comes from property 'foobar' which is declared here on type '{ foobar: (...args: any[]) => Promise<IMessage<{ foobar: (buff: Buffer) => Promise<string>; }, "foobar">>; }'
(property) foobar: (...args: any[]) => Promise<IMessage<{
    foobar: (buff: Buffer) => Promise<string>;
}, "foobar">>

And here are my types:

type EnforcePromise<T, P = any> = T extends Promise<P> ? T : Promise<T>;

type Promised<T> = {
  [P in keyof T]: (...args: InferArgs<T[P]>) => EnforcePromise<InferType<T[P]>>
};

type Filter<T, Cond, U extends keyof T = keyof T> = {
  [K in U]: T[K] extends Cond ? K : never
}[U];

type EventKey<T> = Filter<T, (...args: any[]) => any>;


interface IMessage<T, K extends EventKey<T> = EventKey<T>> {
  type: K;
  payload: InferArgs<T[K]>;
}


export interface ProtocolExtension<T, U, R = {}> {
  name: string;
  type: 'upstream' | 'downstream';
  handlers: Promised<T>;
  messageCreators: {
    [K in keyof U]: (
      ...args: any[]
    ) => Promise<IMessage<U>>
  };
}
4
  • You did not post InferArgs Commented Oct 7, 2018 at 15:40
  • It's like T extends (...args: infer R) => any ? R : never Commented Oct 7, 2018 at 16:05
  • I added the missing types, still can't get your error, since I get Generic type 'ProtocolExtension<T, U, R>' requires between 2 and 3 type arguments. (which is true) could you update your question with a snippet that reproduces your issue ? Commented Oct 7, 2018 at 16:09
  • Here you go bit.ly/2Qy2NiE Commented Oct 7, 2018 at 17:04

1 Answer 1

1

There are two problems in the code both related to the way typescript infers types for literals.

The first one (and the error message you have) is the fact that type: 'foobar' will infer type to be string (in the absence of an imediate reason to infer it to the string literal type 'foobar'). The solution to this is to use a type assertion to the string literal type manually.

After we fix this issue we have a new error on the payload. payload should be InferArgs<T[K]> so it should be tuple with the parameter of the function. You only assign a single value to it. If we were to write [buf] we would have a similar problem to the string literal type issue above. Namely array literal would be typed as an array not a tuple (again in the absence of an imediate reason to type it as a tuple type).

There is also a third issue, the absence of the handelrs property, but taht is probably just an oversight.

const baseUpstreamImpl = (
    client: {},
): ProtocolExtension<
{},
{
    foobar: (buff: {}) => Promise<string>;
}
> => ({
    name: 'base upstream impl',
    type: 'upstream',
    handlers: null as any,
    messageCreators: {
        foobar: (buff: {}) =>
            Promise.resolve({
                type: 'foobar' as 'foobar',
                payload: [buff] as [{}],
            }),
    },
});
Sign up to request clarification or add additional context in comments.

2 Comments

So the as foobar was what I was missing ^^ typescript can be tricky Thanks !
@Vinz243 well, I listed all the things I had to do to get it to compile, that is why a snippet that reproduces the problem and is close to your actual code helps :)

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.