如何优雅地提取和管理Prisma客户端扩展类型

如何优雅地提取和管理prisma客户端扩展类型

本文旨在解决Prisma客户端扩展在模块化时遇到的类型提取难题。通过深入探讨TypeScript的`Parameters`和`Extract`工具类型,我们展示了一种高效的方法来精确定义和分离Prisma客户端扩展的类型,从而提升代码的可维护性和可读性,避免直接在`$extends`方法内部定义复杂类型。

理解Prisma客户端扩展及其类型挑战

Prisma客户端扩展(Client Extensions)是Prisma提供的一项强大功能,允许开发者在不修改Prisma核心客户端的情况下,向其添加自定义逻辑、查询钩子或计算属性。这对于实现业务特定的数据操作、审计日志、权限控制等场景非常有用。

然而,当尝试将这些扩展逻辑模块化到单独的文件中以提高代码可维护性时,开发者常常会遇到类型定义的挑战。Prisma的$extends方法接受一个配置对象,其内部的类型结构会根据具体的模型和操作变得非常复杂。直接从_prismaClient.$extends方法中提取特定扩展部分的类型,并将其应用于独立的模块,并非易事。例如,以下是一个典型的Prisma客户端扩展定义:

// 假设 _prismaClient 是原始的 PrismaClient 实例const prismaClient = _prismaClient.$extends({  query: {    company: {      update: async ({ args, query }) => {        // 业务逻辑:如果公司状态为DECLINED,则锁定相关用户账户        if (args.data?.status === CompanyStatus.DECLINED) {          args.data.user = {            update: {              accountLocked: AccountLockedReason.COMPANY_DECLINED,            },          };        }        return query(args);      },    },  },});

当尝试将company模型的update扩展逻辑分离到一个独立的文件companyExtensions.ts中时,我们需要为其定义正确的类型,以便在主prismaClient.ts文件中引用:

// prismaClient.tsimport { companyExtensions } from './companyExtensions';const prismaClient = _prismaClient.$extends({  query: {    company: companyExtensions, // 需要 companyExtensions 具有正确的类型  },});// companyExtensions.ts// export const companyExtensions: NeedsType = { ... }; // 这里的 NeedsType 是挑战

直接从prismaClient[‘$extends’]的类型中推断出companyExtensions的精确类型,通常会导致一个庞大且难以理解的类型定义,因为它包含了所有可能的扩展点。

解决方案:利用TypeScript工具类型精确提取

解决此问题的关键在于巧妙地结合使用TypeScript的内置工具类型:Parameters和Extract。

Parameters: 这个工具类型用于获取函数类型的所有参数类型,并以元组的形式返回。[0]则表示获取第一个参数的类型。对于_prismaClient.$extends方法,其第一个参数正是我们传递的整个扩展配置对象。

Extract: 这个工具类型用于从Type中提取所有可分配给Union的成员。在这里,我们将使用它来从复杂的扩展配置类型中,筛选出符合我们期望结构(例如,包含name属性,尽管此处name是可选的,但其存在有助于区分不同的扩展配置结构)的部分。

将这两者结合起来,我们可以得到一个简洁且准确的类型定义:

type ExtensionArgs = Extract<  Parameters[0],  { name?: string }>;

这里的{ name?: string }作为一个“标记”或“模式匹配器”,帮助Extract工具类型从$extends方法的第一个参数类型(一个复杂的联合类型或交集类型)中,筛选出那些符合我们通常用来定义客户端扩展的结构。虽然name属性在实际的扩展配置中并非强制,但它提供了一个有效的模式来匹配Prisma扩展的顶层结构。

实施步骤与示例代码

现在,我们可以将上述ExtensionArgs类型应用于我们的模块化扩展定义中。

1. 定义共享类型(推荐在单独的类型文件中)

创建一个types.ts或类似的类型定义文件:

// src/types/prisma.ts (或任何你喜欢的路径)import { PrismaClient } from '@prisma/client';// 假设 _prismaClient 是你原始的 PrismaClient 实例。// 注意:为了在类型文件中引用它,你可能需要一个“虚拟”实例或一个类型别名。// 最简单的方法是直接从 @prisma/client 导入 PrismaClient 类型。// 如果你有一个自定义的基类,可能需要调整。// 这里我们假设 _prismaClient 是 PrismaClient 的一个实例。// 如果你想避免实际导入 _prismaClient,可以这样定义一个类型:// type BasePrismaClient = InstanceType;// 然后在 ExtensionArgs 中使用 BasePrismaClient['$extends']// 但为了简化,我们直接使用 _prismaClient 的类型。// 假设你有一个 _prismaClient 实例,或者你可以直接使用 typeof PrismaClient// 这里的 _prismaClient 应该指向你实际使用的 PrismaClient 实例或其类型// 示例:如果你有一个 const _prismaClient = new PrismaClient();// 那么 typeof _prismaClient 就是正确的。// 如果你只是想定义类型,可以这样模拟:declare const _prismaClient: PrismaClient; // 这是一个类型声明,不会生成运行时代码export type ExtensionArgs = Extract<  Parameters[0],  { name?: string } // 使用 name?: string 作为模式匹配,匹配Prisma扩展的顶层结构>;

2. 模块化你的客户端扩展

在companyExtensions.ts文件中,使用ExtensionArgs来定义你的扩展对象。

// src/extensions/companyExtensions.tsimport { CompanyStatus, AccountLockedReason } from '@prisma/client'; // 假设这些枚举已定义import { ExtensionArgs } from '../types/prisma'; // 导入定义的类型// 精确指定 company 模型的 query.update 扩展类型// 我们可以通过 ExtensionArgs 进一步推断出具体模型的扩展类型// 实际操作中,Prisma的类型推断通常足够智能,// 但为了明确和分离,我们可以在这里直接应用更通用的 ExtensionArgs// 然后让TypeScript在组合时进行验证。// 这里的 companyExtensions 必须符合 ExtensionArgs 的部分结构// 更精确的做法是只导出 query.company 的部分export const companyExtensions: ExtensionArgs['query']['company'] = {  update: async ({ args, query }) => {    if (args.data?.status === CompanyStatus.DECLINED) {      args.data.user = {        update: {          accountLocked: AccountLockedReason.COMPANY_DECLINED,        },      };    }    return query(args);  },};

3. 组合客户端扩展

在主prismaClient.ts文件中,导入并使用这些模块化的扩展。

// src/prismaClient.tsimport { PrismaClient } from '@prisma/client';import { companyExtensions } from './extensions/companyExtensions';const _prismaClient = new PrismaClient();export const prismaClient = _prismaClient.$extends({  query: {    company: companyExtensions, // 类型现在可以正确推断和验证  },  // 可以继续添加其他模型的扩展});export type ExtendedPrismaClient = typeof prismaClient;

通过这种方式,companyExtensions对象现在拥有了明确的类型定义,并且与_prismaClient.$extends方法的期望完全匹配。这大大提高了代码的可读性和可维护性,使得团队成员可以更容易地理解和修改独立的扩展逻辑,而无需深入分析复杂的Prisma内部类型。

注意事项与最佳实践

_prismaClient的类型来源: 在ExtensionArgs的定义中,typeof _prismaClient至关重要。确保它指向你项目中实际使用的PrismaClient实例的类型。如果你在类型文件中无法直接访问一个运行时实例,可以声明一个declare const _prismaClient: PrismaClient;来提供类型信息。name?: string的用途: Extract中的{ name?: string }是一个巧妙的技巧。Prisma客户端扩展的配置对象,尤其是通过defineExtension创建的,通常会有一个可选的name属性。即使你的匿名扩展没有显式设置name,这个模式匹配也足以帮助Extract筛选出正确的顶层扩展配置类型。细化类型: 虽然ExtensionArgs提供了顶层类型,但你可能希望为更深层次的扩展(例如query.company)创建更具体的类型。在companyExtensions.ts中,我们使用了ExtensionArgs[‘query’][‘company’]来进一步细化,这使得类型定义更加精确和安全。Prisma defineExtension: Prisma也提供了defineExtension函数,主要用于创建可分发的通用扩展。虽然它能帮助定义扩展,但对于特定于应用模型的细粒度args类型,可能不如直接使用$extends结合Parameters/Extract来得灵活和直接。

总结

通过巧妙运用TypeScript的Parameters和Extract工具类型,我们可以有效地从Prisma客户端的$extends方法中提取出精确的扩展配置类型。这使得将复杂的客户端扩展逻辑模块化成为可能,极大地提升了大型Prisma项目中的代码组织、可读性与可维护性。这种方法不仅解决了类型定义上的挑战,也促进了更清晰的代码结构和团队协作效率。

以上就是如何优雅地提取和管理Prisma客户端扩展类型的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1537812.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
如何解决React/JSX中自定义标签的类型声明问题
上一篇 2025年12月21日 04:27:54
JS函数如何定义函数兼容性处理_JS函数兼容性处理定义与polyfill使用方法
下一篇 2025年12月21日 04:28:04

相关推荐

  • sublime怎么设置成便携版_Sublime Text创建与使用Portable便携版本

    sublime怎么设置成便携版_Sublime Text创建与使用Portable便携版本sublime怎么设置成便携版_Sublime Text创建与使用Portable便携版本sublime怎么设置成便携版_Sublime Text创建与使用Portable便携版本sublime怎么设置成便携版_Sublime Text创建与使用Portable便携版本

    下载Sublime Text便携版.zip并解压;2. 在解压目录创建Data文件夹;3. 启动sublime_text.exe即进入便携模式,所有配置自动存于Data内;4. 通过复制Data文件夹可实现设置备份与迁移,无需安装或注册表修改,跨设备使用便捷。 Sublime Text 本身不提供官…

    2026年9月28日 • 用户投稿
    000
  • Web无插件RTSP视频流直播系统EasySearcher探测工具无法运行是什么原因?

    Web无插件RTSP视频流直播系统EasySearcher探测工具无法运行是什么原因?Web无插件RTSP视频流直播系统EasySearcher探测工具无法运行是什么原因?Web无插件RTSP视频流直播系统EasySearcher探测工具无法运行是什么原因?Web无插件RTSP视频流直播系统EasySearcher探测工具无法运行是什么原因?

    easynvr分为硬件版本和软件版本,两者的功能基本一致。然而,硬件版本的配置需要额外进行探索和接入步骤才能完成部署。探索功能需要使用tsingsee青犀视频自主研发的easysearcher探测工具,该工具可以在easynvr的官方网站上下载。 在某些情况下,EasySearcher探测工具可能会…

    2026年9月28日 • 用户投稿
    100
  • 乌鲁木齐银行定向采购 Oracle、IBM、Redhat

    2022年2月18日,乌鲁木齐银行发布《正版oracle软件采购项目》公开询价公告,控制价 283 万元。 采购内容:主要目标为以数量授权模式采购,采购Oracle数据库6C,Oracle weblogic 4C,Oracle集群2C,Oracle ADG 2C。 2022年3月1日发布成交公告,新…

    2026年9月28日
    000
  • 抖音价格保护是什么意思?抖音有价格保护吗

    抖音价格保护是什么意思?抖音有价格保护吗抖音价格保护是什么意思?抖音有价格保护吗抖音价格保护是什么意思?抖音有价格保护吗抖音价格保护是什么意思?抖音有价格保护吗

    随着短视频平台的迅猛发展,抖音早已不只是一个娱乐工具,更成为集内容与电商于一体的综合性平台。越来越多用户选择在抖音购物,但随之而来的问题也引发了关注:刚买完商品会不会马上降价?有没有价格保障机制?今天我们就来深入解析“抖音是否有价格保护”以及“价格保护到底意味着什么”。 一、什么是抖音的价格保护? …

    2026年9月28日 • 用户投稿
    000
  • MBTI测试免费链接入口_ MBTI免费测试网站在线地址

    MBTI测试免费链接入口_ MBTI免费测试网站在线地址MBTI测试免费链接入口_ MBTI免费测试网站在线地址MBTI测试免费链接入口_ MBTI免费测试网站在线地址MBTI测试免费链接入口_ MBTI免费测试网站在线地址

    MBTI测试免费链接入口包括www.16personalities.com和www.16mbti.cn,前者基于荣格理论提供16种人格类型分析,含职业建议;后者支持多次测试、生成多维度报告,具社交分享功能,界面简洁适配多设备,测试约12分钟完成。 MBTI测试免费链接入口在哪里?这是不少网友都关注的…

    2026年9月28日 • 用户投稿
    000
  • sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解

    sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解

    掌握Sublime Text多光标与列编辑技巧可大幅提升效率:1. 按Ctrl/Cmd点击或Ctrl+Alt+方向键添加多光标;2. 用Ctrl+D选相同词,Ctrl+Shift+L拆分多行;3. Shift+Alt拖动实现列选择;4. 应用于批量加符号、生成代码、对齐数据等场景。 Sublime …

    2026年9月28日 • 用户投稿
    100
  • 如何用豆包AI写协程代码 协程代码的AI编写技巧大公开

    如何用豆包AI写协程代码 协程代码的AI编写技巧大公开如何用豆包AI写协程代码 协程代码的AI编写技巧大公开如何用豆包AI写协程代码 协程代码的AI编写技巧大公开如何用豆包AI写协程代码 协程代码的AI编写技巧大公开

    用豆包ai写协程代码的关键在于提问方式与后续优化。一、明确所需协程类型,如并发下载或任务管理,提问越具体生成代码越实用;二、注意避免阻塞调用,如将time.sleep改为await asyncio.sleep;三、善用提示词提升代码质量,如指定库、并发数及异常处理;四、结合项目结构调整代码,适配模块…

    2026年9月28日 • 用户投稿
    200
  • 电脑长时间不关机会对硬件造成不可逆损伤吗?

    电脑长时间不关机会对硬件造成不可逆损伤吗?电脑长时间不关机会对硬件造成不可逆损伤吗?电脑长时间不关机会对硬件造成不可逆损伤吗?电脑长时间不关机会对硬件造成不可逆损伤吗?

    长时间不关机不会造成不可逆损伤,但会加速硬件老化。持续运行导致散热系统、机械硬盘、电源电容等部件损耗加剧,尤其是风扇磨损和高温环境下电容老化,影响整体寿命。虽然现代硬件设计成熟,具备保护机制,但长期高温运行仍会缩短CPU、GPU周边元件及SSD写入寿命。相较之下,频繁开关机的热胀冷缩影响较小,适度重…

    2026年9月28日 • 用户投稿
    000
  • 如何用豆包AI生成Python环境配置代码

    如何用豆包AI生成Python环境配置代码如何用豆包AI生成Python环境配置代码如何用豆包AI生成Python环境配置代码如何用豆包AI生成Python环境配置代码

    豆包ai可辅助生成python环境配置代码。1. 首先明确项目需求,如python版本、依赖库和虚拟环境类型;2. 向豆包ai输入具体提示词,获取创建venv和requirements.txt的命令;3. 如需复杂配置,可要求生成开发与生产环境分离的依赖文件;4. 注意版本控制、输出验证及通过多轮交…

    2026年9月28日 • 用户投稿
    100
  • windows8桌面右键新建菜单很卡怎么办_windows8右键菜单卡顿修复方法

    右键菜单卡顿因注册表冗余或软件冲突,需清理ContextMenuHandlers项、删除非New子项、用搜索功能查Directory路径并删多余项,卸载360或NVIDIA等第三方软件,更新显卡蓝牙驱动解决。 如果您在Windows 8桌面上右键点击时,新建菜单响应缓慢或出现卡顿现象,这通常与系统右…

    2026年9月28日
    200
  • JPype集成Aspose.Cells:解决Java堆内存溢出错误指南

    JPype集成Aspose.Cells:解决Java堆内存溢出错误指南JPype集成Aspose.Cells:解决Java堆内存溢出错误指南JPype集成Aspose.Cells:解决Java堆内存溢出错误指南JPype集成Aspose.Cells:解决Java堆内存溢出错误指南

    当Python程序通过JPype调用Java库(如Aspose.Cells)处理大型文件时,可能遭遇java.lang.OutOfMemoryError: Java heap space。本文将详细指导如何通过在jpype.startJVM()中配置JVM的最大堆内存参数来有效解决此类问题,确保Py…

    2026年9月28日 • 用户投稿
    200
  • 豆包AI生成项目预算表的技巧 快速规划资源投入的指南

    豆包AI生成项目预算表的技巧 快速规划资源投入的指南豆包AI生成项目预算表的技巧 快速规划资源投入的指南豆包AI生成项目预算表的技巧 快速规划资源投入的指南豆包AI生成项目预算表的技巧 快速规划资源投入的指南

    做项目预算的关键是明确目标与合理分类。首先需明确项目目标和范围,向豆包ai输入一句话生成初步预算框架;其次将预算分为人力、技术、外包等清晰类别,并用工具生成参考表格;三要为每项预算预留弹性空间,尤其ai项目的不确定性环节;四要定期更新对比预算,利用豆包ai的协作功能跟踪变化并分析调整。 ☞☞☞AI …

    2026年9月28日 • 用户投稿
    100
  • 如何通过服务禁用减少系统启动时间?

    如何通过服务禁用减少系统启动时间?如何通过服务禁用减少系统启动时间?如何通过服务禁用减少系统启动时间?如何通过服务禁用减少系统启动时间?

    精简开机自启动服务可显著缩短系统启动时间。通过禁用非必要的第三方或冗余服务,减轻系统引导负担,释放CPU、内存等资源,提升整体响应速度与电池续航。在Windows中使用services.msc或任务管理器管理服务与启动项,Linux下则用systemctl命令控制服务启停。操作时应从第三方软件入手,…

    2026年9月28日 • 用户投稿
    300
  • 使用 Java 泛型实现 CSV 到对象的转换器

    使用 Java 泛型实现 CSV 到对象的转换器使用 Java 泛型实现 CSV 到对象的转换器使用 Java 泛型实现 CSV 到对象的转换器使用 Java 泛型实现 CSV 到对象的转换器

    本文将介绍如何使用 Java 泛型创建一个通用的 CSV 到对象的转换器。通过泛型,我们可以避免为每种需要转换的 Java 类编写重复的代码,从而提高代码的可重用性和可维护性。文章将提供代码示例,并讨论一些关于代码设计和现有 CSV 解析库的建议。 泛型 CSV 工具类 使用 Java 泛型可以创建…

    2026年9月28日 • 用户投稿
    100
  • sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义

    sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义

    使用Ctrl+R或Cmd+R调用内置符号跳转功能,可快速定位当前文件的函数、类等定义;通过安装CTags、Symbol Browser或SublimeCodeIntel等插件,能实现跨文件跳转与更精准识别;配合LSP插件启用Goto Definition(F12),可获得类似IDE的智能跳转体验,显…

    2026年9月28日 • 用户投稿
    400
  • 电脑安全模式的作用

    电脑安全模式的作用电脑安全模式的作用电脑安全模式的作用电脑安全模式的作用

    电脑安全模式的功能解析: 清除顽固文件 在Windows系统中,当我们尝试删除某些文件或清空回收站时,可能会遇到提示「某文件正在使用中,无法删除」的情况。尽管文件实际上并未被使用,此时可尝试重启电脑,并在启动时进入安全模式。进入安全模式后,Windows会自动释放这些文件的控制权,从而顺利将其删除。…

    2026年9月28日 • 用户投稿
    200
  • sublime怎么使用多光标_Sublime Text多光标编辑高效操作技巧

    sublime怎么使用多光标_Sublime Text多光标编辑高效操作技巧sublime怎么使用多光标_Sublime Text多光标编辑高效操作技巧sublime怎么使用多光标_Sublime Text多光标编辑高效操作技巧sublime怎么使用多光标_Sublime Text多光标编辑高效操作技巧

    Sublime Text 的多光标功能是提升编辑效率的核心工具之一。通过合理使用,可以同时在多个位置进行输入、修改或选择,大幅减少重复操作。 1. 快速添加多个光标 想要同时编辑多个地方,关键是快速在目标位置创建光标: 按住 Ctrl(Cmd)点击**:在不同位置点击鼠标左键,每次点击都会增加一个光…

    2026年9月28日 • 用户投稿
    100
  • 怎么用豆包AI帮我解析XML数据 XML数据解析的AI实现方法详解

    怎么用豆包AI帮我解析XML数据 XML数据解析的AI实现方法详解怎么用豆包AI帮我解析XML数据 XML数据解析的AI实现方法详解怎么用豆包AI帮我解析XML数据 XML数据解析的AI实现方法详解怎么用豆包AI帮我解析XML数据 XML数据解析的AI实现方法详解

    xml数据解析借助豆包ai可简化为四个步骤:1. 发送xml内容让ai分析结构,明确标签层级与关键节点;2. 要求ai生成对应语言的解析代码,如python使用elementtree提取数据;3. 利用ai检查并修复格式错误,如未闭合标签或缺失引号;4. 指定需提取字段及输出格式,如json或csv…

    2026年9月28日 • 用户投稿
    100
  • firefox浏览器如何导出密码 Firefox浏览器密码数据导出备份指南

    firefox浏览器如何导出密码 Firefox浏览器密码数据导出备份指南firefox浏览器如何导出密码 Firefox浏览器密码数据导出备份指南firefox浏览器如何导出密码 Firefox浏览器密码数据导出备份指南firefox浏览器如何导出密码 Firefox浏览器密码数据导出备份指南

    首先通过Firefox账户同步功能可将密码加密上传至云端,登录账户并开启密码同步即可在多设备间自动同步;其次在about:logins页面可手动导出登录数据为未加密CSV文件用于本地备份或迁移;最后高级用户可通过访问配置文件目录提取logins.json和key4.db文件实现对密码数据库的直接备份…

    2026年9月28日 • 用户投稿
    100
  • 图片生成3d效果图的ai工具2025前十榜单

    2025年图片生成3D效果图的AI工具将由多模态理解、高效三维重建与用户友好性领先的平台主导,核心在于简化建模流程、提升真实感与可编辑性,融合NeRF、高斯泼溅与扩散模型等技术,实现从2D图像到高质量3D资产的智能转换,赋能设计、游戏、电商等领域。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索…

    2026年9月28日
    400

发表回复

登录后才能评论
关注微信