2
votes

I updated my typescript packages via npm and now I'm getting the error:

"TS2345: Argument of type '(response: string) => void' is not assignable to parameter of type '((value: {}) => void | PromiseLike) | null | undefined'"

when trying to compile the following code:

private _send<T>(urlPath: string, params?: RequestParams): Promise<T> {
    return this._requester.sendRequest<T>(this._datafeedURL, urlPath, params);
}

public getServerTime(callback: ServerTimeCallback): void {
    this._send('time')
        .then((response: string) => {
            const time = parseInt(response);
            if (!isNaN(time)) {
                callback(time);
            }
        })
        .catch((error?: string | Error) => {
            logMessage(`Failed to load server time, error=${getErrorMessage(error)}`);
        });
}

The error is coming from the .then line

I've read other similar questions but I can't make sense of the issue for my case.

1
Can you show us the _send method body? Or at least what its return type is?CRice
Thanks, but now we need to go deeper. Typescript is failing to infer the type of T, so it's getting a default type of {} (which is too broad, causing the issue you're seeing). To see why that inference isn't working, we need to know the signature of this._requester.sendRequest. What is the type of this._requester, and if possible, can you post the code for its sendRequest method? Or if it's from a library, can you tell us which?CRice
It really looks like you should say this._send<string>('time').jcalz

1 Answers

4
votes

The signature

_send<T>(urlPath: string, params?: RequestParams): Promise<T>;

takes returns a Promise<T>, which has a then() method whose first argument is a callback taking a parameter of type T. If you don't know what promises are, you should read about them. The five-second explanation is that a Promise<Foo> is an object that will eventually hold a Foo object at some point in the future, and you tell it (with the then() method) what it should do with that Foo object when it finally gets it.

Since you are calling then() with a callback function whose parameter is a string, you need T to be assignable to string. The easiest way for this to happen is if T is string.

So what do you have to do with _send() to get T to equal string? Notice that neither urlPath nor params depend on T. That means there's almost no way for the compiler to infer any value for T. And it looks like it's defaulting to the empty object type {}, which tends to happen when TypeScript can't infer any value for a type parameter. Type argument inference (see the Handbook section on generics and look for "type argument inference" for more info) is not going to happen.

You are left with explicitly specifying the type parameter, by calling

this._send<string>('time')

This should allow your then call to compile successfully. Beware that by explicitly setting the type parameter T to string you are trusting that the asynchronous call will actually return a string at runtime. The signature of _send() does seemingly guarantee that it will return a Promise<T> for any value of T that the caller specifies, but obviously it cannot really do that at runtime. So be careful.

Hope that's of some help. Good luck!