achow
achow

Reputation: 1025

Typescript Promise chaining - changing the returned type

I have two async gets I'd like to call, the second which uses the output of the first one, and their returned types (within the Promise) are different.

These are from the AsyncStorage library in React.

My code is:

    function fetchAllSecretsRaw(): Promise<[string, string | null][]> {
        return AsyncStorage.getAllKeys().then((allKeys) => {
            return AsyncStorage.multiGet(allKeys.filter(isSecretKey));
        });
    }

I am surprised that this typechecks when looking at the Promise declaration. How does this work? How can Promise<[string, string | null][]> satisfy Promise<string[]> (which comes from TResult1 = T?

The async functions signatures are:

getAllKeys(callback?: (error?: Error, keys?: string[]) => void): Promise<string[]>;

  multiGet(
    keys: string[],
    callback?: (errors?: Error[], result?: [string, string | null][]) => void
  ): Promise<[string, string | null][]>;

while .then on a Promise<T> is:

    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
        onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

The first getAllKeys() gives me a Promise<string[]>, which according to the Promise declaration means that T=string[]

Since TResult1 = T (from then's declaration then<TResult1 = T,) does that mean TResult1 = string[]?

But the onfulfilled function I pass actually returns a Promise<[string, string | null][]>, i.e. a tuple array instead of a string array.

Upvotes: 1

Views: 840

Answers (2)

Bergi
Bergi

Reputation: 664538

the .then declaration also constrains that TResult1 = T

No, it doesn't constrain it (like an extends clause would) - that's only a default value for when no onfulfilled callback is provided.

But you did provide one, and its type is (value: string[]) => Promise<[string, string | null][]>, so TResult1 is properly inferred to [string, string | null][].

Upvotes: 1

Lodewijk Bogaards
Lodewijk Bogaards

Reputation: 19987

TResult1 is the type of the return value of the onfulfilled function (in your case [string, string | null][]) OR if onfulfilled is absent the type of T (in your case string[]).

Since your onfulfilled function is:

(allKeys) => {
  return AsyncStorage.multiGet(allKeys.filter(isSecretKey));
}

which returns a Promise<[string, string | null][]>. This therefore type checks fine. It is not a mistake.

Upvotes: 2

Related Questions