【问题标题】:How to type a recursive intersection, with refactor in mind?如何在考虑重构的情况下键入递归交集?
【发布时间】:2022-11-10 19:26:06
【问题描述】:

我正在尝试重构以下代码,以便我可以以类型安全的方式在多个页面上重用相同的中间件逻辑。但是,我很难编写适用于以下用例的类型安全递归类型。

工作原始代码:

import { NextPage, GetServerSidePropsContext } from 'next';

// new InferGetServerSidePropsType fix, waiting for merge to stable
type InferGetServerSidePropsType<T extends (args: any) => any> = Awaited<
  Extract<Awaited<ReturnType<T>>, { props: any }>['props']
>;

const getServerSideProps = async (context: GetServerSidePropsContext) =>
  (async (context, props) => {
    const token = 'token';
    if (Math.random() > 0.5)
      return {
        notFound: true,
      };
    return (async (context, props) => {
      if (context.locale === 'en')
        return {
          redirect: {
            destination: '/en',
            permanent: true,
          },
        };
      const permissions = [1, 2, 3];
      return (async (context, props) => {
        const data = 'data';
        return { props: { ...props, data } };
      })(context, { ...props, permissions });
    })(context, { ...props, token });
  })(context, {});

const MyPage: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (props) => {
  const { token, permissions, data } = props; // types are infered correctly!
  return null;
};

Playground code

在我第一次尝试键入中间件之间的递归交集时,我得到了这个损坏的代码:


const withToken: GSSPMiddleware<{ token: string }> = (next) => async (context, props) => {
  if (Math.random() > 0.5)
    return {
      notFound: true,
    };
  const token = 'token';
  return next(context, { ...props, token });
};

const withPermissions: GSSPMiddleware<{ permissions: number[]}> = (next) => async (context, props) => {
  if (context.locale === 'en')
    return {
      redirect: {
        destination: '/en',
        permanent: true,
      },
    };
  const permissions = [1, 2, 3];
  return next(context, { ...props, permissions });
};

const getServerSideProps = async (context: GetServerSidePropsContext) =>
  withToken(
    withPermissions(async (context, props) => { // props: {token: string} & {permissions: number[]}
      const data = "data";
      return { props: { ...props, data } };
    })
  )(context, {});

const MyPage: NextPage<InferGetServerSidePropsType<typeof getServerSideProps>> = (props) => {
  const { token, permissions, data } = props; // types should infer correctly!
  return null;
};

// My attempt, completely wrong
type GSSPMiddleware<Params extends { [key: string]: any } | undefined = undefined> = <
  P extends { [key: string]: any } = { [key: string]: any },
>(
  next: (
    context: GetServerSidePropsContext,
    props: Params extends undefined ? P : P & Params
  ) => Promise<GetServerSidePropsResult<Params extends undefined ? P : P & Params>>
) => (
  context: GetServerSidePropsContext,
  props: P
) => Promise<GetServerSidePropsResult<Params extends undefined ? P : P & Params>>;

我应该如何重构这段代码并编写这种类型?

【问题讨论】:

  • 缺少ParseUrlQuery 的定义。
  • this 你的问题是什么?由于所有额外的 Next.js 特定的 BS,很难说出发生了什么。它会大大如果您可以将问题简化为不需要 Next.js 特定内容的示例,则可以提供帮助。就像在我的示例中一样,我尝试在不需要 Next.js 的情况下复制您的问题。它是公正的还是我错过了什么?
  • 我在这里有一个类型安全的多中间件解决方案 stackblitz.com/edit/nextjs-eqqhbs?file=pages%2Fapi%2Fhello.ts 。不确定您是否可以使用 1:1 但这是一个好的开始

标签: typescript next.js


【解决方案1】:
type PropsType<T> = T extends {props: infer P} ? P:never;

export type InferGetServerSidePropsType<T extends (args: any) => any> = PropsType<Awaited<ReturnType<T>>>

这确实推断出类型,但数据结构有点令人困惑,所以我不确定我是否错过了任何东西^^告诉我它是否有效

【讨论】:

    猜你喜欢
    • 2010-12-31
    • 1970-01-01
    • 2010-11-26
    • 2015-02-28
    • 1970-01-01
    • 2013-11-13
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    相关资源
    最近更新 更多