类型“void”上不存在属性。

3

我正在编写一个钩子来进行发出POST请求,并返回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时,我会收到一个错误,该错误表明sessionData不存在于void类型上。但是,如果我检查控制台上的日志,则在组件和钩子上都会得到相同的对象。此外,如果我检查数据的类型,我会得到一个对象。
为什么会出现这个错误?

3
你的catch块中没有返回任何内容,因此你的函数的返回类型是WhateverTheTypeOfResponseIs | void,具体取决于哪个代码路径执行。你在使用JavaScript还是TypeScript?你从哪里得到了这个错误信息?是来自VSCode的智能提示吗? - Jared Smith
1
是的,错误来自Intellisense,我正在使用TypeScript。在我看来,Promise<void>是TypeScript编译器推断的默认类型。当我尝试为异步函数的返回类型进行类型标注时,会出现“Type WhateverTheTypeOfResponseIs is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value”的错误提示。由于我从组件中调用钩子函数createOrder,所以我也没有落入catch块中。实际上,如果我检查组件的类型,我也会得到一个对象。 - l.legren
3
建议将错误处理逻辑放在 useEffect 钩子内,在调用 .catch 时处理错误,例如 createOrder().then(...).catch(...)。然后简化你的 createOrder 函数,只需简单地返回 postWithToken(...)。另外,createOrder 不是一个钩子(hook)-它只是一个简单的函数。 - goto
3
看起来你正在使用 TypeScript,但没有提供 createOrder 的返回类型,例如 createOrder = async (): Promise<SomeType>,这就是为什么出现了错误提示。 - goto
3个回答

3
你的catch块没有返回任何内容,所以你的函数的返回类型是Promise<WhateverTheTypeOfResponseIs | void>(注意:async函数隐式返回一个Promise,如果你的postWithToken函数没有返回任何内容,则只是Promise<void>),具体取决于哪个代码路径发生了。将来,你可以通过给函数指定显式的返回类型来避免这样不愉快且稍微有点棘手的调试问题,在这种情况下,编译器会让你知道你的期望被违反了:
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)
  }
}

游乐场

我创建的示例中的类型可能不同(您需要使用代码中的实际类型进行替换),但您应该可以理解。您可以通过以下任何一种方式修复此问题:
  1. 从catch块显式返回正确类型的内容。
  2. 将返回类型更改为Promise<CorrectType | undefined>
  3. 按照goto1在评论中建议的将错误处理移动到调用者。
另外请注意,正如goto1在问题的评论中指出的那样,您的钩子实际上并不是一个钩子(这很好,但要小心术语)。

1
这听起来像是一个 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 */)
  }, [])
}

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接