我正在构建一个云功能,它将使用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);
}
}
答案 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)