如何指定泛型类型的泛型参数?TypeScript模型类型丢失问题
解决TypeScript泛型构建器保留模型自定义类型的问题
你的问题核心在于调用pickOnly后,构建器返回的模型类型被直接替换成了BaseModel,丢失了原自定义模型(比如CustomModel)的方法和成员。要解决这个问题,我们需要让构建器在调整属性类型的同时,保留原模型的类型结构。
解决方案步骤
- 定义类型替换工具:创建一个
ReplaceModelAttributes类型,用来替换模型的属性泛型参数,同时保留原模型的所有自定义成员。 - 修改构建器方法:让
pickOnly返回包含原模型类型变体的Builder,而不是直接返回BaseModel。
修改后的完整代码
/** * 基础数据模型类 */ class BaseModel<T extends Record<string, any>> { private data: T = {} as T; getAttribute<K extends keyof T>(key: K): T[K] { return this.data[key]; } } /** * 自定义数据模型类,包含自定义方法 */ class CustomModel extends BaseModel<{ foo: string, bar: number }> { someMethod() { } } // 提取模型的属性类型 type GetAttributes<M extends BaseModel<any>> = M extends BaseModel<infer A> ? A : never; // 挑选指定属性并将其他属性设为null type PickAndNullifyOthers<T, K extends keyof T> = { [P in keyof T]: P extends K ? T[P] : null; }; // 从构建器中提取模型类型 type GetModelFromBuilder<T> = T extends Builder<infer M> ? M : never; // 替换模型的属性泛型参数,保留原模型的自定义成员 type ReplaceModelAttributes<M extends BaseModel<any>, A extends Record<string, any>> = M extends BaseModel<infer _> ? { new(): Omit<M, keyof BaseModel<any>> & BaseModel<A> } : never; /** * URL构建器类,支持挑选模型的特定属性 */ class Builder<T extends BaseModel<any>> { pickOnly<K extends keyof GetAttributes<T>>(key: K): Builder<InstanceType<ReplaceModelAttributes<T, PickAndNullifyOthers<GetAttributes<T>, K>>>> { return {} as any; } }
测试使用示例
const wrapper = new Builder<CustomModel>() .pickOnly('foo'); // 仅挑选foo属性,其他属性设为null const model = {} as GetModelFromBuilder<typeof wrapper>; const fooResult = model.getAttribute('foo'); // 类型:string const barResult = model.getAttribute('bar'); // 类型:null model.someMethod(); // 不再报错,保留了CustomModel的方法
原理说明
ReplaceModelAttributes类型通过条件类型,提取原模型的非BaseModel成员(比如someMethod),并将其与替换了属性泛型的BaseModel<A>合并,确保原模型的自定义方法不会丢失。InstanceType将构造函数类型转换为实例类型,符合Builder泛型对BaseModel子类实例的要求。- 修改后的
pickOnly方法返回的Builder泛型类型,是原自定义模型的变体,既调整了属性类型,又保留了所有自定义成员。
内容的提问来源于stack exchange,提问作者Matej
相关产品推荐
相关产品推荐

