如何实现MongoDB WithId的TypeScript泛型变体WithStrId?
实现自定义的WithStringId泛型(为类型添加string类型的_id字段)
MongoDB的TypeScript库自带的WithId泛型用起来很方便——不用修改现有接口或类型,就能直接适配MongoDB的文档结构,示例代码如下:
export class TagsCl { private publicTags: Promise<Array<WithId<ProductTag>>>; private allTags: Promise<Array<WithId<ProductTag>>>; private tags: Collection<ProductTag>; constructor(){ //... } //... }
现在需要一个类似的泛型(比如命名为WithStrId或WithStringId),实现相同的适配逻辑,但给现有类型强制添加类型为string的_id字段,用于前端开发。原WithId的实现考虑了很多MongoDB相关的复杂场景,代码如下:
/** TypeScript Omit (Exclude to be specific) does not work for objects with an "any" indexed type, and breaks discriminated unions @public */ export declare type EnhancedOmit<TRecordOrUnion, KeyUnion> = string extends keyof TRecordOrUnion ? TRecordOrUnion : TRecordOrUnion extends any ? Pick<TRecordOrUnion, Exclude<keyof TRecordOrUnion, KeyUnion>> : never; export declare type InferIdType<TSchema> = TSchema extends { _id: infer IdType; } ? Record<any, never> extends IdType ? never : IdType : TSchema extends { _id?: infer IdType; } ? unknown extends IdType ? ObjectId : IdType : ObjectId; export declare type WithId<TSchema> = EnhancedOmit<TSchema, '_id'> & { _id: InferIdType<TSchema>; };
最简实现方式
前端场景不需要处理MongoDB的ObjectId和复杂类型兼容,直接用TypeScript原生的Omit工具类型就能实现,代码极简:
type WithStringId<T> = Omit<T, '_id'> & { _id: string };
逻辑说明
Omit<T, '_id'>:移除原类型T中可能存在的_id字段(不管它原来是什么类型)& { _id: string }:通过交叉类型强制添加一个类型为string的_id字段,确保最终类型的_id一定是字符串类型- 完全覆盖前端开发的需求,不需要原
WithId里针对MongoDB的复杂推断逻辑
使用示例
假设你有一个ProductTag接口:
interface ProductTag { name: string; color: string; }
使用WithStringId后:
// 最终类型为 { name: string; color: string; _id: string } type ProductTagWithId = WithStringId<ProductTag>; // 在类中使用的示例 export class TagsCl { private publicTags: Promise<Array<WithStringId<ProductTag>>>; private allTags: Promise<Array<WithStringId<ProductTag>>>; //... }
内容的提问来源于stack exchange,提问作者x0a
相关产品推荐
相关产品推荐

