为啥此语句会引发打字稿错误?
Posted
技术标签:
【中文标题】为啥此语句会引发打字稿错误?【英文标题】:Why does this statement throw a typescript error?为什么此语句会引发打字稿错误? 【发布时间】:2021-11-14 22:22:26 【问题描述】:以下语句引发类型错误。为什么?
const x: Chat = ...doc.data(), id: doc.id
错误是:
输入 ' id: string; ' 缺少“聊天”类型的以下属性:消息、名称、createdAt ts(2739)
展开操作数提供对象的三个元素,id由第二个操作数提供。
我正在使用 Vue 3.0.0、firebase 9.0.2 和 typescript 4.1.5
这是整个组件:
import ref from 'vue'
import projectFirestore, Timestamp from '@/firebase/config'
// import Chat from '@/types/Chat'
interface Chat
id?: string
message: string
name: string | null
createdAt: Timestamp
import
collection as collect,
query,
orderBy,
onSnapshot,
from 'firebase/firestore'
const getCollection = (collection: string) =>
const documents = ref<Chat[]>()
const error = ref<string>()
try
const q = query(
collect(projectFirestore, collection),
orderBy('createdAt', 'desc')
)
const unsubscripe = onSnapshot(q, (querySnapshot) =>
const results: Chat[] = []
querySnapshot.forEach((doc) =>
const x: Chat = ...doc.data(), id: doc.id
doc.data().createdAT && results.push(x)
)
documents.value = results
)
catch (err)
if (err instanceof Error)
error.value = err.message
else
throw Error('Unknown Error')
return documents, error
export default getCollection
我是打字稿的新手,但这看起来确实很奇怪。提前致谢
【问题讨论】:
该错误告诉您 TypeScript 为doc.data()
提供的类型不提供缺少的属性。这可能是因为 TypeScript 只是不知道类型是什么,或者类型错误。 doc.data()
附近似乎没有任何类型信息——doc
没有类型注释,querySnapshot
没有类型注释,onSnapshot
没有类型注释。我怀疑onSnapshot
是一个通用函数,它默认为querySnapshot
(以及doc
)提供特定类型的通用类型参数,但我不使用Firebase。这就是我要看的地方。
如果您将鼠标悬停在 doc.data()
上,您的 IDE 可能会告诉您 TypeScript 认为它返回的类型。
请注意,doc.data().createdAT
将始终为 undefined
,因为您的字段实际上是 createdAt
。尽量避免过度键入并使用withConverter()
和FirestoreDataConverter
来执行您的类型断言。另外不要忘记将监听器的取消订阅功能返回给调用者,您还应该在onSnapshot
上添加错误处理回调。
谢谢 - 我将使用下面建议的类型断言。
感谢@samthecodingman。我正在尝试学习Typescript和Firebase.Firestore,并在我正在构建的Vue 3应用程序中使用它们作为基于YouTube的课程的练习,该课程在我使用v9时使用了firebase v8。证明具有挑战性,但很有趣。非常感谢您的 cmets,我将研究您提到的转换器。再次感谢
【参考方案1】:
正如@TJCrowder 评论的那样,您可以检查data()
方法返回的内容。它返回 DocumentData
类型的对象,而 Typescript 并不真正知道内容是什么。您可以尝试使用这样的类型断言,并指定对象的类型为Chat
:
const x = ...doc.data(), id: doc.id as Chat
但是,这可能会导致错误输入不存在的文档(当 doc.exists === false
- 通常在使用 DocumentReference
而不是查询时发现)。您可以断言您在查询中使用的CollectionReference
的类型,而不是断言doc.data()
行上的类型。这同样适用于DocumentReference
。 Typescript 将确保您首先正确处理了文档不存在的情况。
collect(projectFirestore, collection) as CollectionReference<Chat>
// ...
// x will be a Chat object when `doc.exists === true` (which it is in queries)
const x = ...doc.data(), id: doc.id
您可以在 Typescript 的 documentation 中阅读有关 Type Assertion
的更多信息。
【讨论】:
谢谢。使用类型断言是可行的,现在就足够了。我误解了这个信息,但现在我明白了。有趣的是,这应该是一个通用组件,但对于 typescript 来说,这要简单得多。我可以导入每个类型并在断言之前测试我正在检索的类型,或者使用任何破坏目的的类型。我需要考虑一下。 @maxweld 如果您知道要获取哪些文档,您就知道类型,因此使用类型断言似乎很好 @maxweld 与我提到的使用FirestoreDataConverter
的方式相关,您可以欺骗CollectionReference 以认为您使用了CollectionReference<DataType>
和DocumentReference<DataType>
。虽然您可以这样做,但请确保类型是您对 Firestore 的期望(例如,您的自定义类型可能有一个 Date 对象,但 Firestore 发送了一个 Timestamp 对象)。我已将此信息添加到 Dharmaraj 的答案中。
感谢@samthecodingman 的编辑。我只是考虑了所有匹配的文档都存在的 QuerySnapshot 案例?♂️以上是关于为啥此语句会引发打字稿错误?的主要内容,如果未能解决你的问题,请参考以下文章