为啥此语句会引发打字稿错误?

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&lt;DataType&gt;DocumentReference&lt;DataType&gt;。虽然您可以这样做,但请确保类型是您对 Firestore 的期望(例如,您的自定义类型可能有一个 Date 对象,但 Firestore 发送了一个 Timestamp 对象)。我已将此信息添加到 Dharmaraj 的答案中。 感谢@samthecodingman 的编辑。我只是考虑了所有匹配的文档都存在的 QuerySnapshot 案例?‍♂️

以上是关于为啥此语句会引发打字稿错误?的主要内容,如果未能解决你的问题,请参考以下文章

模块导入忽略了打字稿`esModuleInterop`

为啥打字稿不显示错误? (反应)

打字稿错误对象可能为空?为啥,如何禁用?

如何在打字稿中使用 rxjs6 分区?

当 /// 引用在“use strict”之后时,为啥打字稿会抱怨?

如何在打字稿中设置初始 React 状态?