口头出版的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 itself的section已经记录了这一部分。为此,我们将使用TypeScript提供的模块扩展,该模块允许用户覆盖他/她无法访问的类型的类,模块,类型(也许来自LIB)。为此,
-
我们可以在 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提供的用户的默认属性。 -
然后在 /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
上所做的那样。 -
因此,回到 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)。但是有一些方法可以获取这些类型:
-
使用像这样的prisma客户端方法的返回类型
const getById = async () => await prisma.post.findUnique({ //.... }) type Post = ReturnType<typeof getById>
-
或者您可以使用模型类型的
GetPayload
版本,我们可以在其中指定此模型与其他模型之间的所有关系
import { PrismaClient, Prisma } from "@prisma/client"; type User = Prisma.UserGetPayload<{ // here you can specify all relations like: select, include, ... }>
我不推荐您这些解决方案,因为我们有 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发布的文章。免费尝试。