讲师中心 微信公众号
AI工具推荐 视频效率加速

Prisma Client 扩展的类型提取与模块化实践

老磊小哥_8676

老磊小哥_8676

发布时间:2025-11-10 17:00:24

|

492人浏览过

|

来源于php中文网

原创

Prisma Client 扩展的类型提取与模块化实践

本文旨在解决prisma client扩展在进行模块化重构时遇到的类型定义难题。通过深入探讨typescript的类型推断机制和prisma `$extends`方法的内部类型结构,我们将演示如何精确地提取并定义分离的扩展模块类型,从而提升代码的可维护性和可读性,并提供清晰的实现步骤和示例代码。

引言:Prisma Client 扩展与模块化需求

Prisma Client 扩展提供了一种强大机制,允许开发者在不修改核心Client代码的情况下,为数据库操作添加自定义逻辑,例如在查询执行前后插入业务规则。随着项目复杂性增加,将所有扩展逻辑集中在一个大型对象中会导致代码难以维护和阅读。因此,将扩展逻辑拆分到独立文件中进行模块化管理成为必然需求。然而,这一过程中的主要挑战在于如何为这些分离的扩展模块精确地定义TypeScript类型。

挑战:分离扩展的类型定义

当我们将Prisma Client扩展(特别是针对特定模型查询的扩展)从主$extends调用中抽离出来时,TypeScript的类型推断能力往往难以直接为这些独立的对象提供准确的类型。例如,考虑以下将company模型查询扩展分离的场景:

// prismaClient.ts
import { PrismaClient } from '@prisma/client';
import { companyExtensions } from './extensions/companyExtensions'; // 尚未定义类型

const _prismaClient = new PrismaClient();

const prismaClient = _prismaClient.$extends({
  query: {
    company: companyExtensions, // 这里 companyExtensions 的类型需要明确
  },
});

// companyExtensions.ts
// 如何为 companyExtensions 定义精确的类型?
export const companyExtensions: unknown = { // 这里的 unknown 是待解决的问题
  update: async ({ args, query }) => {
    // 示例业务逻辑
    if (args.data?.status === 'DECLINED') {
      args.data.user = {
        update: {
          accountLocked: 'COMPANY_DECLINED',
        },
      };
    }
    return query(args);
  },
};

直接尝试使用Parameters[0]可能会得到一个过于宽泛或难以直接应用于嵌套对象的复杂类型。Prisma 官方提供的defineExtension函数主要面向通用、可分发的扩展,其设计目标并非为特定模型操作提供精细的args类型推断。因此,我们需要一种更精确的方法来提取这些内部扩展的类型。

解决方案:利用 Parameters 和 Extract 提取类型

解决此问题的关键在于利用TypeScript的内置工具类型Parameters和Extract,结合Prisma Client的内部类型结构。我们的目标是首先获取传递给_prismaClient.$extends方法的完整参数类型,然后从中精确地提取出我们所需的部分。

1. 获取完整的扩展参数类型

首先,我们需要获取_prismaClient.$extends方法接受的参数的类型。这里的_prismaClient指的是未经过任何扩展的原始Prisma Client实例。

// 定义一个基础的Prisma Client实例(仅用于类型推断)
import { PrismaClient } from '@prisma/client';
const _prismaClientForTypeInference = new PrismaClient();

// 获取 $extends 方法的参数类型
type FullExtensionArgs = Parameters<typeof _prismaClientForTypeInference.$extends>[0];

FullExtensionArgs将是一个复杂的联合类型或交叉类型,它包含了Prisma Client扩展可能接受的所有结构。

2. 精确提取目标扩展类型

由于FullExtensionArgs可能非常通用,我们需要使用Extract工具类型来将其窄化到我们实际使用的扩展结构。Extract会从UnionType中提取所有可赋值给MemberType的成员。在这里,我们通常会使用一个包含name?: string属性的对象字面量来“锚定”或选择出代表客户端扩展配置的特定类型分支。

type ExtensionArgs = Extract<FullExtensionArgs, { name?: string }>;

经过这一步,ExtensionArgs现在代表了传递给$extends方法的整个配置对象的类型,其中包含了query、model、client等顶级属性及其对应的复杂类型。

Scrapfly SDK TypeScript
Scrapfly SDK TypeScript

使用 Scrapfly SDK(scrapfly-sdk)在 TypeScript 或 JavaScript 中进行网页抓取,用于用户请求抓取 URL、绕过反爬虫防护、渲染页面等场景。

下载

3. 提取特定模型查询扩展的类型

现在,我们已经有了整个扩展配置的类型ExtensionArgs,接下来就可以从中访问我们需要的特定模型查询扩展的类型。在我们的例子中,companyExtensions是query.company下的一个对象。

type CompanyQueryExtension = ExtensionArgs['query']['company'];

CompanyQueryExtension现在精确地表示了company模型下所有查询扩展的类型,包括update方法及其内部的args和query参数的正确类型。

实践:模块化 Prisma Client 扩展

下面是结合上述类型提取方法,实现Prisma Client扩展模块化的完整示例。

1. src/extensions/companyExtensions.ts 文件

首先,在单独的文件中定义companyExtensions,并使用我们刚刚提取的CompanyQueryExtension类型。

// src/extensions/companyExtensions.ts
import { PrismaClient } from '@prisma/client';

// 注意:这个 _prismaClientForTypeInference 实例仅用于类型推断,不应在运行时实际使用。
// 它的目的是提供一个未扩展的 PrismaClient 类型上下文,以便 TypeScript 能够正确推断 $extends 的参数类型。
const _prismaClientForTypeInference = new PrismaClient();

// 步骤1: 获取 $extends 方法的完整参数类型
type FullExtensionArgs = Parameters<typeof _prismaClientForTypeInference.$extends>[0];

// 步骤2: 精确提取目标扩展类型
type ExtensionArgs = Extract<FullExtensionArgs, { name?: string }>;

// 步骤3: 提取特定模型查询扩展的类型
export type CompanyQueryExtension = ExtensionArgs['query']['company'];

export const companyExtensions: CompanyQueryExtension = {
  update: async ({ args, query }) => {
    // 示例业务逻辑:如果公司状态被设置为 DECLINED,则锁定关联用户的账户
    if (args.data?.status === 'DECLINED') {
      args.data.user = {
        update: {
          accountLocked: 'COMPANY_DECLINED',
        },
      };
    }
    return query(args); // 继续执行原始的 update 操作
  },
  // 可以在这里添加其他 company 模型的查询扩展,例如 findMany, create 等
  // findMany: async ({ args, query }) => { /* ... */ return query(args); }
};

通过这种方式,companyExtensions对象现在拥有了正确的类型定义,并且其内部的update方法的args和query参数都将获得Prisma提供的精确类型提示。

2. src/prismaClient.ts 文件

然后,在主Prisma Client实例化文件中引入并使用这个分离的扩展模块。

// src/prismaClient.ts
import { PrismaClient } from '@prisma/client';
import { companyExtensions } from './extensions/companyExtensions'; // 导入分离的扩展

const _prismaClient = new PrismaClient(); // 实际的未扩展Prisma Client实例

export const prismaClient = _prismaClient.$extends({
  query: {
    company: companyExtensions, // 直接使用导入的扩展对象
  },
  // 可以添加其他模型或客户端级别的扩展
  // model: { /* ... */ },
  // client: { /* ... */ }
});

// 导出扩展后的客户端供应用程序使用
export type PrismaClientExtended = typeof prismaClient;

现在,prismaClient实例将包含companyExtensions中定义的逻辑,并且整个设置在TypeScript层面是完全

热门AI工具

更多
二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

相关专题

更多
TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

312

2026.02.13

TypeScript全栈项目架构与接口规范设计
TypeScript全栈项目架构与接口规范设计

本专题面向全栈开发者,系统讲解基于 TypeScript 构建前后端统一技术栈的工程化实践。内容涵盖项目分层设计、接口协议规范、类型共享机制、错误码体系设计、接口自动化生成与文档维护方案。通过完整项目示例,帮助开发者构建结构清晰、类型安全、易维护的现代全栈应用架构。

520

2026.02.25

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

391

2026.03.13

TypeScript 全栈开发进阶指南
TypeScript 全栈开发进阶指南

面向有 JavaScript 基础的开发者,深入讲解 TypeScript 的类型系统与全栈开发实践。

286

2026.06.03

TypeScript Node.js 全栈工程化与Monorepo架构实践
TypeScript Node.js 全栈工程化与Monorepo架构实践

本专题围绕 TypeScript 在 Node.js 全栈开发中的工程化实践展开,系统讲解 Monorepo 架构设计、包管理策略、模块复用机制以及服务端与前端统一类型系统的构建方法。通过真实项目案例,帮助开发者提升大型全栈项目的可维护性与协作效率。

658

2026.06.16

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

6779

2023.08.02

JavaScript中的typeof用法
JavaScript中的typeof用法

在JavaScript中,typeof是一个用来确定给定变量的数据类型的操作符。可以用来确定一个变量是字符串、数字、布尔值、函数、对象或undefined的数据类型。更多关于typeof用法相关文章,详情请看本专题下面的文章,php中文网欢迎大家前来学习。

8587

2023.11.23

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

2885

2023.06.29

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

20

2026.10.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

TypeScript 教程
TypeScript 教程

共19课时 | 6.7万人学习

TypeScript——十天技能课堂
TypeScript——十天技能课堂

共21课时 | 1.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn