Pesquisa de site

Erro do Firebase Cloud Function em TypeScript: "Nem todos os caminhos do código retornam um valor"


Estou usando a função em nuvem do Firebase e transação do Firestore para diminuir a quantidade disponível de produto com base nas compras. No momento do deploy, retorna o erro "error TS7030: Nem todos os caminhos de código retornam um valor"

Aqui está o código

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';


admin.initializeApp();
const db = admin.firestore()

exports.newOrder = functions.firestore
.document('orders/{orderId}')
.onCreate(async (snap, context) => {

    try {
        const data = snap.data();
        if (data === undefined) return null

        const itemList = data.list as Array<any>
        const productId: Set<string> = new Set<string>();

        itemList.forEach((item) => {
            productId.add(item.id)
        })
        return db.runTransaction(async t => {

            const promises: Promise<admin.firestore.DocumentSnapshot>[] = []
            productId.forEach(i => {
                const p = admin.firestore().doc('Products/' + i).get()
                promises.push(p)
            })
            const docs=await Promise.all(promises)
            docs.forEach(doc => {
                if (!doc.exists) {
                    return Promise.reject("Product deleted")
                }
            })
            itemList.forEach(j => {
                if (j.variation === '-') {
                    const available = docs[j.id].get('available')
                    const needed = j.quantity
                    if (available < needed) {
                        return Promise.reject("Product out of stock")
                    }
                }
                else {
                    const variations = docs[j.id].get('variation') as Map<string, any>
                    for (const i in variations.keys) {
                        if (i === j.variation) {
                            const needed = j.quantity
                            const available = docs[j.id].get('variation').get(i).get('quantity')
                            if (available < needed) {
                                return Promise.reject("Product out of stock")
                            }
                        }
                    }
                }
            })
            itemList.forEach(j => {
                if (j.variation === '-') {
                    const available = docs[j.id].get('available')
                    const needed = j.quantity
                    t.update(db.doc('Products/' + j.id), { 'available': available - needed })
                }
                else {
                    const variations = docs[j.id].get('variation') as Map<string, any>
                    for (const i in variations.keys) {
                        if (i === j.variation) {
                            const needed = j.quantity
                            const available = docs[j.id].get('variation').get(i).get('quantity')
                            t.update(db.doc('Products/' + j.id), { [`variation.${i}.quantity`]: available - needed })
                        }
                    }
                }
            })
            return Promise.resolve("Product quantity updated")
        })
    }
    catch (error) {
        console.log(`error ${error}`)
        return null
    }
});

Aqui está o erro mostrado na implantação

 src/index.ts:30:30 - error TS7030: Not all code paths return a value.

 30                 docs.forEach(doc => {
                            ~~~~~~~~

 src/index.ts:35:34 - error TS7030: Not all code paths return a value.

 35                 itemList.forEach(j => {
                                ~~~~~~


 Found 2 error 

Como resolver o erro.

2 loops mencionados no erro verificam se o produto foi excluído ou não e se o produto está fora de estoque ou não. Se atender à condição, quero sair da função. Por favor, me ajude.

Resposta #1

A mensagem de erro está dizendo que há funções que não retornam um valor em todas as situações. Ela está até dizendo quais funções estão violando esse requisito. Aqui está o primeiro erro:

 src/index.ts:30:30 - error TS7030: Not all code paths return a value.

 30                 docs.forEach(doc => {
                            ~~~~~~~~

Está dizendo que a função que você está passando para o forEach está tendo um problema.

Aqui está a função:

        docs.forEach(doc => {
            if (!doc.exists) {
                return Promise.reject("Product deleted")
            }
        })

Observe que a função não está retornando um valor quando doc.exists é verdadeiro. Se você não se importar com essa situação, apenas retorne null:

        docs.forEach(doc => {
            if (!doc.exists) {
                return Promise.reject("Product deleted")
            }
            else {
                return null
            }
        })

Agora o erro desaparece, porque todos os caminhos do código retornam um valor. Você pode aplicar a mesma lógica ao outro erro.

Resposta #2

O problema é mais profundo do que pode parecer. Você possivelmente está entendendo mal o que a instrução return faz dentro do forEach. O código está estruturado como se assumisse que fosse verificar se algum dos doc.exists é falso e retornar cedo nesse caso, mas escrito assim, ele irá retornar da função de callback da iteração... e como o forEach não utiliza o valor de retorno da callback, a rejeição da promessa continua sem ser tratada.

As maneiras adequadas de alcançar este resultado seriam as seguintes:

1) Apenas verifique diretamente o que você precisa verificar:

if (docs.findIndex(doc => !doc.exists) !== -1) {
    return Promise.reject("Product deleted");
}

2) Use o loop for..in ou for..of em vez de forEach:

for (doc of docs) {
    if (!doc.exists) {
        return Promise.reject("Product deleted")
    }
}

3) Use o map e await o resultado (não recomendado, já que você realmente não precisa de mapeamento):

await Promise.all(docs.map(doc => {
    if (!doc.exists) {
        return Promise.reject("Product deleted")
    }
    return null
})

Observe que, neste caso, qualquer promessa rejeitada dentro do array resultante deve acionar a rejeição da promessa externa.

Observação: você nunca precisa da chamada explícita Promise.reject(). Como sua função é assíncrona, você pode simplesmente throw algo que usará como erro - isso será transformado em rejeição de promessa de qualquer forma.

Artigos relacionados