如何在TypeScript声明文件中用用户传入值作为类型键
解决Prisma扩展的TypeScript声明与参数类型映射问题
一、用泛型实现参数值作为类型键
核心是利用TypeScript的泛型和索引类型捕获用户传入的idFieldName,将其作为其他类型的键。
1. 主声明文件(index.d.ts)
// 定义带泛型的扩展配置接口 interface PrismaExtensionConfig<IdField extends string> { idFieldName: IdField; } // 基于泛型参数生成目标类型 type IdField<IdField extends string> = { [K in IdField]: string | number }; type IdFieldKey<IdField extends string> = IdField; // 高阶函数类型定义,避免污染原函数签名 declare function createPrismaExtension<IdField extends string>( config: PrismaExtensionConfig<IdField> ): (prisma: Prisma.Client) => Prisma.Client & { method_1: (args: MyMethod1Args<IdField>) => Promise<void>; };
2. 方法声明文件(method_1.d.ts)
import type { IdFieldKey } from './index'; // 用泛型参数约束参数的键 type MyMethod1Args<IdField extends string> = { [K in IdFieldKey<IdField>]: string | number; otherArg?: string; };
二、适配高阶函数的JS代码类型
保留JS的高阶函数结构,通过JSDoc补全泛型类型,实现逐步迁移:
/** * 创建Prisma扩展 * @template {string} IdField * @param {import('./index').PrismaExtensionConfig<IdField>} config * @returns {(prisma: import('@prisma/client').PrismaClient) => import('@prisma/client').PrismaClient & { method_1: (args: import('./method_1').MyMethod1Args<IdField>) => Promise<void> }} */ function createPrismaExtension(config) { return (prisma) => { return { ...prisma, async method_1(args) { // 业务逻辑中直接使用config.idFieldName const idValue = args[config.idFieldName]; // ... } }; }; } module.exports = createPrismaExtension;
三、解决esbuild未检测到的声明文件错误
- 确保所有声明文件的泛型参数传递一致,避免类型不匹配
- 在
tsconfig.json中配置include字段,覆盖所有.d.ts文件:
{ "include": ["src/**/*.js", "src/**/*.d.ts"] }
- 用
tsc --noEmit预先检查声明文件的类型错误,esbuild不做全量类型校验,需手动提前排查
四、逐步迁移策略
- 先为核心JS文件补全JSDoc泛型,匹配声明文件的类型定义
- 逐步将复杂逻辑的JS文件重写为TS,替换对应声明文件
- 保留现有业务代码不动,只在类型层做兼容调整
内容的提问来源于stack exchange,提问作者philolegein
相关产品推荐
相关产品推荐

