使用T3堆栈时的一些提示:第1部分
#javascript #nextjs #prisma #trpc

口头出版的here

可能是这些技巧与T3堆栈无关,而是涉及其使用的堆栈

在我的上一个article中,我介绍了我正在构建的附带项目和我正在使用的工具(堆栈)。并解释为什么我选择T3 Stack来构建该项目。很好,在本文中,我将分享一些我在构建项目时使用T3堆栈发现的提示。让我们走!

提醒

  • NextAuth需要/用于身份验证的模型用户,具有一些预配置列,例如名称,图像,电子邮件等。

  • 在T3堆栈中,我们将Prisma用作ORM

  • 我们已经为用户模型添加了一些列,例如用户名

NextAuth和模块扩展

NextAuth在Next.js应用程序中用于身份验证,并包装在T3堆栈中。使用NextAuth时,Hook useSession返回可以检查的会话数据以验证是否有人签名:

const index = () => {
    const { data: session } = useSession()
    if (session) {
        return <div>You're signed as {session.user.email}</div>    
    }
    return <div>Not signed, we'll redirect you</div>
}

但是出于安全原因,会话数据(默认为默认)仅包含

export interface DefaultSession {
    user?: {
        name?: string | null;
        email?: string | null;
        image?: string | null;
    };
    expires: ISODateString;
}

那么,如果我们想添加一个新属性(例如用户名),我们该怎么办,该属性是我们用Prisma定义的用户模型的一列?

T3专用于NextAuth和NextAuth itselfsection已经记录了这一部分。为此,我们将使用TypeScript提供的模块扩展,该模块允许用户覆盖他/她无法访问的类型的类,模块,类型(也许来自LIB)。为此,

  1. 我们可以在 next-auth模块中覆盖会话接口在文件中声明 types/next-auth.d.t.ts。

    import { DefaultSession } from "next-auth";
    
    declare module "next-auth" {
      interface Session {
        user?: {
          id: string;
          username: string | null  
        } & DefaultSession["user"];
      }
    }
    

    我们不仅添加username,还可以合并默认设备中的用户类型,从而导入next-auth模块并覆盖会话接口,因此我们仍然拥有NextAuth提供的用户的默认属性。

  2. 然后在 /pages/api/auth/[... nextauth] .ts 文件中,我们可以通过添加username这样的

    来覆盖会话回调。

    callbacks: {
        session({ session, user }) {
          if (session.user) {
            session.user.id = user.id;
            session.user.username = user.username;
          }
          return session;
        },
      },
    

    但是,如果您这样留下,您将从ts:Property 'username' does not exist on type 'User | AdapterUser'获得此警告。为什么?

    因为,如果您转到User的TS定义(NextAuth使用),您会发现它扩展了具有以下定义(最小值)的DefaultUser

    export interface DefaultUser {
        id: string;
        name?: string | null;
        email?: string | null;
        image?: string | null;
    }
    

    因此,要解决此错误,我认为您猜该解决方案,是的:覆盖User的声明,就像我们在Session上所做的那样。

  3. 因此,回到 types/next-auth.d.ts, 我们可以在Session接口之后覆盖User(insex auth ofer next-auth声明),如

      interface User extends DefaultUser{
        username: string | null
      }
    

    我们只是首先扩展了DefaultUser(由NextAuth提供),然后添加username

让我们移到另一个提示。

型号类型扣除(使用TRPC)

使用Prisma,我们将表定义为 schema.prisma 文件中的模型,但是我们在TypeScript中无法直接访问其类型,因为它生成了类型的定义在 node_modules/.prisma/client/index.d.ts 默认情况下(如果要更改此输出文件位置,请阅读此link)。但是有一些方法可以获取这些类型:

  1. 使用像这样的prisma客户端方法的返回类型

    const getById = async () => await prisma.post.findUnique({
    //....
    })
    
    type Post = ReturnType<typeof getById>
    
  2. 或者您可以使用模型类型的GetPayload版本,我们可以在其中指定此模型与其他模型之间的所有关系

    import { PrismaClient, Prisma } from "@prisma/client";
    type User = Prisma.UserGetPayload<{
        // here you can specify all relations like: select, include, ...
    }>
    

    您可以阅读更多here和此link

我不推荐您这些解决方案,因为我们有 trpc (不要怪我)。

在我们的情况下,我们通过TRPC使用Prisma客户端。而且您会很高兴知道TRPC具有推断路由器的输入/返回类型的实用程序。假设我们有一个名为user的路由器,我们在该路由器内定义了一个过程retrieve。要获取此过程的PLAIN TRPC的返回类型:

import type { inferRouterInputs } from "@trpc/server"

type User = inferRouterInputs<AppRouter>['user']['retrieve']

很好!但是,如果我说在T3堆栈中有一个小帮助人可以使此操作更容易:
您将如何:

import {RouterOutputs} from "@utils/api";
type User = RouterOutputs['project']['getById']

是的,如果您去看 @utils/api 您会看到

export type RouterOutputs = inferRouterOutputs<AppRouter>;

无论如何,使用柔软。

奖金:

使用这种方法,ts可以使您温暖User类型可能为null,因此为了避免使用NonNullable实用程序:

import {RouterOutputs} from "@utils/api";
type User = NonNullable<RouterOutputs['project']['getById']>

对!

结论

我喜欢我们从TRPC获得的端到端类型,与T3堆栈一起工作非常酷

我们在本文的最后。我希望你喜欢它。如果我在建立SaaS时得到另一个提示,我将分享。欢迎反馈或任何有助于我改进这篇文章的内容。

使用bloggu.io发布的文章。免费尝试。