TypeScript+Vue3:返回含reactive和ref变量的可组合函数应设置什么返回类型?
解决方案
首先你需要先从Vue中导入Ref类型,用来标注ref()创建的变量类型,有两种实现方案可选:
方案1:固定类型声明(适合简单场景)
直接显式声明返回对象的两个固定属性的类型,完全匹配你当前的代码逻辑,无需修改其他内部代码:
// 第一步:导入Ref类型 import { ref, reactive, watchEffect, type Ref } from "vue"; import { projectFirestore } from "@/firebase/config"; import { query, orderBy, onSnapshot, DocumentData, collection, } from "firebase/firestore"; // 第二步:替换原来的any为显式返回类型 const useCollection = (collectionPath: string): { documentsArray: Record<string, unknown>[], error: Ref<string | null> } => { const documentsArray = reactive<Record<string, unknown>[]>([]); const error = ref<string | null>(null); // 剩余代码完全不变 const collectionReference = collection(projectFirestore, collectionPath); const collectionOrdered = query( collectionReference, orderBy("createdAt", "desc") ); const unsubscribe = onSnapshot( collectionOrdered, (snapshot) => { documentsArray.splice(0); snapshot.forEach((doc: DocumentData) => { documentsArray.push({ ...doc.data(), id: doc.id }); }); error.value = null; }, (err) => { console.log(err.message); documentsArray.splice(0); error.value = err.message; } ); watchEffect((onInvalidate) => { console.log("watchEffect fired"); onInvalidate(() => { console.log("onInvalidate fired"); unsubscribe(); }); }); return { documentsArray, error }; }; export default useCollection;
方案2:泛型声明(推荐,适配后续扩展)
如果后续你需要对不同集合做类型约束,可以用泛型实现更灵活的类型推导,使用时可以传入对应集合的类型定义:
import { ref, reactive, watchEffect, type Ref } from "vue"; // 其他导入不变 // 泛型默认值为Record<string, unknown>,不传泛型也能正常使用 const useCollection = <T extends Record<string, unknown> = Record<string, unknown>>(collectionPath: string): { documentsArray: T[], error: Ref<string | null> } => { // 修改reactive的类型为泛型数组 const documentsArray = reactive<T[]>([]); const error = ref<string | null>(null); // 中间逻辑不变 const collectionReference = collection(projectFirestore, collectionPath); const collectionOrdered = query( collectionReference, orderBy("createdAt", "desc") ); const unsubscribe = onSnapshot( collectionOrdered, (snapshot) => { documentsArray.splice(0); snapshot.forEach((doc: DocumentData) => { // 增加类型断言匹配泛型 documentsArray.push({ ...doc.data(), id: doc.id } as T); }); error.value = null; }, (err) => { console.log(err.message); documentsArray.splice(0); error.value = err.message; } ); watchEffect((onInvalidate) => { console.log("watchEffect fired"); onInvalidate(() => { console.log("onInvalidate fired"); unsubscribe(); }); }); return { documentsArray, error }; }; // 使用示例:假设用户集合的类型为User // interface User { // id: string; // name: string; // age: number; // createdAt: Date; // } // const { documentsArray: users, error } = useCollection<User>('users') // 此时users会自动推导为User[]类型
为什么你之前的尝试会报错
你之前尝试使用Record<string, unknown>作为返回类型会报错,是因为该类型代表所有键为字符串、值为unknown的任意对象,TypeScript无法从中推导documentsArray和error两个固定属性的存在,也匹配不上ref创建的Ref包装类型,所以会触发类型不匹配错误。
内容的提问来源于stack exchange,提问作者TinyTiger
相关产品推荐
相关产品推荐

