In the following code, the only difference between getDocsWithIdThatWorks
and getDocsWithIdThatComplains
is the callback they are passing to Array.prototype.map
. In one case it's a function expression, and in the other it's an overloaded, generic function. In the first case, TypeScript perfectly understands and agrees about the return type of the overloaded function. But when passing the overloaded function's reference directly as an argument to Array.prototype.map
, TypeScript suddenly infers the return type as DocumentWithId<unknown>
, despite the fact that the array being mapped is clearly typed as QueryDocumentSnapshot<T>
. Why is that so?
interface DocumentSnapshot<T> {
id: string
data(): T | undefined
}
interface QueryDocumentSnapshot<T> extends DocumentSnapshot<T> {
data(): T
}
interface DocumentWithId<T> {
id: string
data?: T
}
interface QueryDocumentWithId<T> {
id: string
data: T
}
function withId<T>(document: QueryDocumentSnapshot<T>): QueryDocumentWithId<T>
function withId<T>(document: DocumentSnapshot<T>): DocumentWithId<T>
function withId<T>(document: DocumentSnapshot<T> | QueryDocumentSnapshot<T>): DocumentWithId<T> | QueryDocumentWithId<T> {
return {
id: document.id,
data: document.data(),
}
}
type Query<T> = () => Promise<QueryDocumentSnapshot<T>[]>
async function getDocsWithIdThatWorks<T>(query: Query<T>): Promise<QueryDocumentWithId<T>[]> {
const result = await query()
return result.map((d) => withId(d))
}
async function getDocsWithIdThatComplains<T>(query: Query<T>): Promise<QueryDocumentWithId<T>[]> {
const result = await query()
return result.map(withId)
}