如何为Firebase Cloud Function的TypeScript钩子正确定义输入输出类型?
问题
我正在使用Firebase Cloud Functions,通过React应用调用服务端代码。我有多个不同的函数,每个函数接收不同的输入参数,并返回带有各种属性的data对象。
我希望创建一个名为useFirebaseFunctions.ts的钩子,用于发起请求,同时能明确查看该函数所需的所有输入参数和预期输出结果。
我在钩子中编写了以下函数:
async function generateReport({ organisationId, projectId }: { organisationId: string; projectId: string; }): Promise<{ data: { id: string; fileName: string; numOfRows: number; createdOn: number; }; }> { const request = httpsCallable(functions, 'adminFunctions-generateReport'); return request({ organisationId, projectId }); }
adminFunctions-generateReport函数的参数如下:
| 输入 | 输出 |
|---|---|
| organisationId: string | id: string |
| projectId: string | fileName: string |
| numOfRows: number | |
| createdOn: number |
TypeScript在return request({...});行显示错误:
Type 'HttpsCallableResult' is not assignable to type '{ data: { id: string; fileName: string; numOfRows: number; createdOn: number; }; }'. Types of property 'data' are incompatible. Type '{}' is missing the following properties from type '{ id: string; fileName: string; numOfRows: number; createdOn: number; }': id, fileName, numOfRows, createdOn
请问如何为该函数正确定义类型,实现预期行为且无错误?
解决方案
这个错误的核心是httpsCallable默认返回的HttpsCallableResult类型中,data属性被推断为空对象{},和你定义的返回类型不匹配。你需要给httpsCallable显式指定输入和输出的泛型类型,让TypeScript正确识别请求参数和返回数据的结构。
步骤1:定义输入输出类型(可选但推荐)
先把输入和输出的类型单独定义出来,提高代码可读性和复用性:
// 定义generateReport的输入参数类型 type GenerateReportInput = { organisationId: string; projectId: string; }; // 定义generateReport的返回data类型 type GenerateReportOutputData = { id: string; fileName: string; numOfRows: number; createdOn: number; };
步骤2:给httpsCallable指定泛型
在创建request的时候,给httpsCallable传入输入和输出的泛型参数,这样request调用后返回的HttpsCallableResult就会带有正确的data类型:
async function generateReport({ organisationId, projectId }: GenerateReportInput): Promise<{ data: GenerateReportOutputData }> { // 显式指定泛型:输入类型为GenerateReportInput,输出data类型为GenerateReportOutputData const request = httpsCallable<GenerateReportInput, GenerateReportOutputData>(functions, 'adminFunctions-generateReport'); return request({ organisationId, projectId }); }
直接简化写法(如果不需要单独定义类型)
如果不想单独定义类型,也可以直接在httpsCallable中内联泛型:
async function generateReport({ organisationId, projectId }: { organisationId: string; projectId: string; }): Promise<{ data: { id: string; fileName: string; numOfRows: number; createdOn: number; }; }> { const request = httpsCallable< { organisationId: string; projectId: string }, { id: string; fileName: string; numOfRows: number; createdOn: number } >(functions, 'adminFunctions-generateReport'); return request({ organisationId, projectId }); }
核心原因
httpsCallable的泛型签名是httpsCallable<InputData = {}, ResponseData = {}>(...): HttpsCallable<InputData, ResponseData>,默认情况下输入和输出都是空对象。通过显式传入你的实际输入输出类型,TypeScript就能正确推断request()返回的HttpsCallableResult中的data属性结构,和你定义的返回类型匹配,从而消除类型错误。
内容的提问来源于stack exchange,提问作者Sam

