如何解决打字稿错误“对象可能是'未定义'”

时间:2019-03-29 22:49:18

标签: typescript firebase google-cloud-functions stripe-payments

我正在构建一个云功能,它将使用Stripe API来处理付款。这是在firebase项目中。运行firebase deploy时出现错误“对象可能是'undefined'” const existingSource = customer.sources.data.filter( (s) => s.id === source).pop(); 我不确定该如何解决。

这是我的索引。

import * as functions from 'firebase-functions'; 

export { stripeAttachSource } from './sources';
export { stripeCreateCharge, stripeGetCharges } from './charges';
export const testFunction = functions.https.onCall( async (data, context) => {
    const uid = context.auth && context.auth.uid; 
    const message = data.message; 
    return `${uid} sent a message of ${message}`
}); 

这是我的消息来源。

import * as functions from 'firebase-functions';
import { assert, assertUID, catchErrors } from './helpers';
import { stripe } from './config'; 
import { getOrCreateCustomer } from './customers';

/** Attachs a payment source to a stripe customer account.  */
export const attachSource = async(uid: string, source: string) => {

    const customer = await getOrCreateCustomer(uid); 

    const existingSource = customer.sources.data.filter( (s) => s.id === source).pop(); 
    if (existingSource != undefined) {
        let t = existingSource; 
        return t; 
    } else {
        await stripe.customers.createSource(customer.id, { source: source }); 
        //update default
        return await stripe.customers.update(customer.id, { default_source: source}); 
    }
}

///////// DEPLOYABLE FUNCTIONS //////////////////////////////////
export const stripeAttachSource = functions.https.onCall( async ( data, context) => {
    const uid = assertUID(context); 
    const source = assert(data, 'source'); 

    return catchErrors(attachSource(uid, source));  
})

这是存在getorCreateCustomer的customers.ts

import { assert } from './helpers'; 
import {db, stripe } from './config'; 


/** 
Read the user document from Firestore
 */
export const getUser = async(uid: string) => {
    return await db.collection('users').doc(uid).get().then(doc => doc.data()); 

}

/**
 * Gets a customer from Stripe
 */
export const getCustomer = async(uid: string) => {
    const user = await getUser(uid); 
    return assert(user, 'stripeCustomerId'); 
}

/**
Updates the user document non-desctructively
 */
export const updateUser = async(uid: string, data: Object) => {
    return await db.collection('s-users').doc(uid).set(data, { merge: true }); 
}

/**
Takes a Firebase user and creates a Stripe customer account
 */
export const createCustomer = async(uid: any) => {
    const customer = await stripe.customers.create({
        metadata: { firebaseUID: uid }
    })
    await updateUser(uid, {stripeCustomerId: customer.id })

    return customer; 
}

/** Read the stripe customer ID from firestore, or create a new one if missing */
export const getOrCreateCustomer = async(uid: string) => {
    const user = await getUser(uid); 
    const customerId = user && user.stripeCustomerId; 

    //if missing customerId, create it
    if (!customerId) {
        return createCustomer(uid); 
    }
    else {
        return stripe.customers.retrieve(customerId); 
    }
}

enter image description here

3 个答案:

答案 0 :(得分:3)

基于函数的定义和内容,TypeScript无法推断getOrCreateCustomer的返回类型。假设它可能返回未定义,并且其严格模式要求您引用一个未定义对象上的属性的事实,这将在运行时导致错误。

您需要做的是将返回类型声明为无法定义的类型,并确保该函数体中的代码在该保证范围内正确(否则您将得到一个新错误)

如果您不能执行此操作(但您确实应该执行该操作),则可能要在tsconfig.json文件中禁用严格模式,因为这正是在代码中强制达到此正确性级别的原因。

即使您必须编写更多的代码行,我还是建议采用第一种方法,因为它是TypeScript键入系统的更好使用。

答案 1 :(得分:1)

@Doug提到的内容,但您也可以编写逻辑以确保customer.sources.data的每个部分都未定义...

即:

const { sources } = customer

if (sources) {
  const { data } = sources 
  if (data) {
     // then filter / etc etc ...
  }
}

答案 2 :(得分:0)

7个月后,我找到了最佳解决方案。

我只是在以下if / else语句中包装了Firebase可调用函数的内容。这有点多余,但可以。

if (!context.auth) {
    // Throwing an HttpsError so that the client gets the error details.
    throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
        'while authenticated.');
  }
  else{ ...copy function code here }

如果您不关心身份验证项,则可以简单地将上下文类型定义为 any

(data, context:any)