【问题标题】:Property does not exist on type voidvoid 类型不存在属性
【发布时间】:2022-01-27 02:17:02
【问题描述】:

我正在编写一个钩子来发出返回两个属性 sessionIdsessionData 的发布请求。我在一个组件中使用这个钩子。我的钩子是这样的。

export const createOrder = async () => {
  try {
    const response = await postWithToken(API_ROUTES.PAYMENT_SESSION, token || '', 
    testObject)
    console.log("FROM HOOK", response)
    return response
    } catch (err: any) {
      console.log(err)
    }
  }

我的组件看起来像这样

const myComponent = () => {
  useEffect(() => {
    createOrder().then(data => {
      console.log("Session Data",data.sessionData)
      console.log("FROM PAGE", data)
    })
  }, [])

  return (
    <div />
  )
}

当我尝试访问组件上的 data.sessionData 时,我收到 sessionDta 在类型 void 上不存在的错误。但是,如果我检查控制台上的日志,我会在组件和挂钩上得到相同的对象。此外,如果我检查我的组件类型数据,我会得到一个对象。

为什么会出现这个错误?

【问题讨论】:

  • 您不会从 catch 块中返回任何内容,因此您的函数的返回类型是 WhateverTheTypeOfResponseIs | void,具体取决于发生的代码路径。您使用的是 Javascript 还是 Typescript?你是如何/从哪里得到这个错误的? VSCode 智能感知?
  • 是的,错误来自 Intellisense,我正在使用 Typescript。在我看来,Promise&lt;void&gt; 是 Typescript 编译器推断的默认类型。当我尝试键入异步函数的返回值时,我得到一个“类型 WhateverTheTypeOfResponseIs 在 ES5/ES3 中不是有效的 async 函数返回类型,因为它没有引用与 Promise 兼容的构造函数值”。我也没有降落在 catch 块上,因为当我从那里调用钩子 createOrder 时,我得到了组件上的对象。实际上,如果我检查组件上的类型,我也会得到一个对象
  • 当您通过.catch 调用时,我建议您将错误处理逻辑移到useEffect 挂钩中,例如createOrder().then(...).catch(...)。然后将您的createOrder 函数 简化为简单的return postWithToken(...)。此外,createOrder 不是 hook - 它只是一个简单的函数。
  • 另外,看起来您正在使用TypeScript 并且没有提供createOrder 的返回类型,例如createOrder = async (): Promise&lt;SomeType&gt;,这就是它抱怨的原因。

标签: javascript typescript asynchronous hook


【解决方案1】:

你不会从你的 catch 块返回任何东西,所以你的函数的返回类型是 Promise&lt;WhateverTheTypeOfResponseIs | void&gt;(注意 async 函数隐式返回一个 Promise,如果你的 postWithToken 函数没有返回任何东西,那么它就是只是Promise&lt;void&gt;),取决于发生的代码路径。

将来,您可以通过为您的函数提供明确的返回类型来避免调试此类问题时出现令人不快且略有问题的情况,在这种情况下,编译器会通知您违反了您的期望:

const postWithToken = async (route: string, token: string, obj: any): Promise<boolean> => {
  try {
    const resp = await fetch(
      route,
      { 
        method: 'POST',
        body: JSON.stringify(Object.assign(obj, { token }))
      },
    )
    return Boolean(resp.status < 400 && resp.status >= 200)
  } catch (err) {
    console.error(err)
    return false
  }
}

const API_ROUTES = {
    PAYMENT_SESSION: 'whatever'
}

const testObject = {
  token: ''
}

const token = ''

const createOrder = async (): Promise<boolean> => { // <-- squiggles
  try {
    const response = await postWithToken(API_ROUTES.PAYMENT_SESSION, token || '', 
    testObject)
    console.log("FROM HOOK", response)
    return response
  } catch (err: any) {
    console.log(err)
  }
}

Playground

我创建的示例中的类型可能不同(您需要使用代码中的实际类型进行子化),但您应该明白这一点。您可以通过以下任何方式解决此问题:

  1. 从 catch 块中显式返回正确类型的内容。
  2. 将您的返回类型更改为Promise&lt;CorrectType | undefined&gt;
  3. 按照 cmets 中 goto1 的建议,将错误处理移至调用方。

另请注意,正如 goto1 在问题的 cmets 中指出的那样,您的钩子实际上并不是一个钩子(这很好,但要注意术语)。

【讨论】:

    【解决方案2】:

    这听起来像是TypeScript 问题,所以我建议为您的createOrder 函数提供正确的返回类型。

    // Use the official type for SessionData, if you have it available,
    // otherwise create a new type that properly matches its shape
    type CreateOrderResult = {
      sessionData: SessionData;
    }
    
    // No need for `async/await` here, just return the `postWithToken`
    // and handle errors inside your component
    export const createOrder = (): Promise<CreateOrderResult> => {
      // ...
      return postWithToken(
        API_ROUTES.PAYMENT_SESSION, 
        token || '',
        testObject
      )
    }
    
    // MyComponent.tsx
    const MyComponent = () => {
      useEffect(() => {
        createOrder()
          .then(data => console.log(data.sessionData))
          .catch(error => /* handle errors appropriately */)
      }, [])
    }
    

    【讨论】:

      猜你喜欢
      • 2019-12-01
      • 2019-03-18
      • 2018-08-11
      • 2021-08-05
      • 1970-01-01
      • 2021-12-11
      • 2016-12-31
      • 2019-02-04
      • 2018-07-17
      相关资源
      最近更新 更多