TypeScript泛型实现多返回类型的类型安全问题
解决Typegoose多租户多模型的类型推导问题
问题核心
你当前的getModelsForDbWithKey方法无法生成正确的类型提示,原因是缺少针对Schema到模型类型的泛型映射约束,无法让TypeScript自动推导返回值的具体类型。
解决方案
通过定义泛型映射类型和泛型约束,让方法根据传入的Schema键值对,自动推导对应模型的类型。以下是改造后的完整实现:
1. 基础类型定义
先创建一个泛型类型,用于将Typegoose的Schema类映射为对应的模型类型:
import { getModelForClass, ReturnModelType } from '@typegoose/typegoose'; import mongoose from 'mongoose'; // 泛型类型:把Schema类映射为Typegoose模型类型 type SchemaToModel<T> = { [K in keyof T]: ReturnModelType<T[K]>; };
2. 改造多模型获取方法
给方法添加泛型约束,让它接收Schema键值对并返回对应类型的模型集合:
// 租户数据库切换逻辑(假设你已有此实现) function getTenantDb(tenantId: string): mongoose.Connection { return mongoose.connection.useDb(`tenant_${tenantId}`); } // 单个模型获取方法(保留原有逻辑,已支持类型提示) function getModelForDb<T>(clazz: new () => T, tenantId: string): ReturnModelType<typeof clazz> { const db = getTenantDb(tenantId); return getModelForClass(clazz, { existingConnection: db }); } // 改造后的多模型方法,自动推导类型 function getModelsForDbWithKey<T extends Record<string, new () => any>>( schemas: T, tenantId: string ): SchemaToModel<T> { const db = getTenantDb(tenantId); const models: Partial<SchemaToModel<T>> = {}; for (const key in schemas) { if (schemas.hasOwnProperty(key)) { models[key] = getModelForClass(schemas[key], { existingConnection: db }); } } return models as SchemaToModel<T>; }
3. 使用示例
现在调用getModelsForDbWithKey时,每个模型都会自动获得完整的类型提示:
// 定义你的Schema类 class User { name!: string; email!: string; } class Order { userId!: string; amount!: number; } // 获取多模型,TypeScript自动推导类型 const tenantModels = getModelsForDbWithKey({ User, Order }, 'tenant_123'); // 此时tenantModels.User和tenantModels.Order都有完整的智能提示 tenantModels.User.findOne({ name: 'Alice' }); // 类型校验生效 tenantModels.Order.create({ userId: '1', amount: 99 }); // 参数类型自动提示
关键说明
- 泛型映射:
SchemaToModel<T>遍历传入的Schema对象的每个键,将Class类型转换为Typegoose的ReturnModelType,确保返回值类型与输入Schema一一对应。 - 泛型约束:
T extends Record<string, new () => any>确保传入的schemas是合法的Schema类集合。 - 类型断言:方法内部的
as SchemaToModel<T>是因为TypeScript无法自动推断循环赋值后的完整类型,手动断言仅用于类型推导,不影响运行时逻辑。
内容的提问来源于stack exchange,提问作者Manoj Sethi
相关产品推荐
相关产品推荐

