繁体   English   中英

Next.js GetServerSideProps 自定义包装器 TypeScript

[英]Next.js GetServerSideProps custom wrapper TypeScript

我为GetServerSideProps SSR 函数创建了一个包装器以减少重复,但我在使用 TypeScript 正确键入它时遇到了问题。 这是包装:

type WithSessionType = <T extends {}>(
  callback: GetServerSideProps<T>
) => GetServerSideProps<{ session: Session | null } & T>

//                                                 v error
const withSession: WithSessionType = (callback) => async (ctx) => {
  const session = await getSession(ctx)
  const result = await callback?.(ctx)
  const props = result && 'props' in result ? result.props : {}
  return {
    ...result,
    props: {
      session,
      ...props,
    },
  }
}

错误:

Type '(ctx: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>) => Promise<{ props: { session: Session | null; }; redirect: Redirect; } | { ...; } | { ...; }>' is not assignable to type 'GetServerSideProps<{ session: Session | null; } & T, ParsedUrlQuery, PreviewData>'.
  Type 'Promise<{ props: { session: Session | null; }; redirect: Redirect; } | { props: { session: Session | null; }; notFound: true; } | { props: { session: Session | null; }; }>' is not assignable to type 'Promise<GetServerSidePropsResult<{ session: Session | null; } & T>>'.
    Type '{ props: { session: Session | null; }; redirect: Redirect; } | { props: { session: Session | null; }; notFound: true; } | { props: { session: Session | null; }; }' is not assignable to type 'GetServerSidePropsResult<{ session: Session | null; } & T>'.
      Type '{ props: { session: Session | null; }; }' is not assignable to type 'GetServerSidePropsResult<{ session: Session | null; } & T>'.
        Type '{ props: { session: Session | null; }; }' is not assignable to type '{ props: ({ session: Session | null; } & T) | Promise<{ session: Session | null; } & T>; }'.
          Types of property 'props' are incompatible.
            Type '{ session: Session | null; }' is not assignable to type '({ session: Session | null; } & T) | Promise<{ session: Session | null; } & T>'.
              Type '{ session: Session | null; }' is not assignable to type '{ session: Session | null; } & T'.
                Type '{ session: Session | null; }' is not assignable to type 'T'.
                  '{ session: Session | null; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.ts(2322)

用例(有效):

export const getServerSideProps = withSession(async () => {
  return {
    props: {
      custom: 'custom string type',
    },
  }
})

这是getServerSideProps计算类型:

const getServerSideProps: GetServerSideProps<{
    session: Session | null;
} & {
    custom: string;
}, ParsedUrlQuery, PreviewData>

它工作正常,甚至InferGetServerSidePropsType也能​​正确推断类型,但仍然会出现上述错误。

正确的自动完成

知道如何让 TypeScript 在这里开心吗? 如果您有任何关于这种包装器的建议和技巧,也期待着。

更新

我找到了原因,但我不太明白为什么会这样。结果它认为这个陈述总是错误的,即使props可以存在于这种类型上。 在此处输入图像描述

GetServerSidePropsResult 类型:

export type GetServerSidePropsResult<P> =
  | { props: P | Promise<P> }
  | { redirect: Redirect }
  | { notFound: true }

为什么只有redirect在这种类型上可见,而不是propsnotFound

更新 2 - 我正在失去理智

在此处输入图像描述

在此处输入图像描述 为什么T只存在于 2 号?

不太确定,但我认为问题在于 T 可能有另一个会话定义,因此该类型不再可分配。 您可以只使用Omit<T,"session">从 T 中排除会话,或者您可以编写类似<T extends { session?: Session | null > <T extends { session?: Session | null >而不是<T extends {}>

顺便提一句。 {}在实践中的 TS 意味着“任何非空值”,因此您应该考虑使用类似Record<string| number, any> Record<string| number, any>代替

(未测试,写在我的手机上,所以可能有错误)

该问题在另一个问题中进行了描述: 如何修复 TS2322:“可以使用不同的约束‘对象’子类型来实例化”?

我无法理解应该做什么才能让 TS 开心,但我有一个解决方法是强制转换返回的函数而不是声明返回的类型:

function withSession<T extends {}>(callback: GetServerSideProps<T>){
  return (async (ctx) => {
    const session = await getSession(ctx)
    const result = await callback?.(ctx)
    const props = result && 'props' in result ? result.props : {}
    return {
      ...result,
      props: {
        session,
        ...props,
      },
    }
  }) as GetServerSideProps<{ session: Session | null } & T>
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM