如何修正TypeScript代理构建器中build方法的返回类型问题?
问题:构建器build方法返回错误类型,无法返回完整目标类型
我需要实现一个类型构建器,能在构建过程中隐藏指定属性(防止用户修改预设值),目前用代理方案实现后,构建器的build()方法无法返回正确的完整类型——比如预设了type: 'basic'的basicUserBuilder,调用build()后应该返回User类型,但实际返回的是Omit<User, 'type'>。
原代码示例
type ProxyBuilder<Type, SubType = Type> = { [Key in keyof SubType]: (arg: SubType[Key]) => ProxyBuilder<SubType>; } & { build(): Type }; // 此处Type被后续类型覆盖 function proxyBuilder<Type, SubType = Type>( defaultValues?: Partial<Type> ): ProxyBuilder<Type, SubType> { const built: any = { ...defaultValues }; const builder = new Proxy( {}, { get: function (_target, prop) { if (prop === 'build') return () => built as Type; return (value: any) => { built[prop] = value; return builder as SubType; }; }, } ); return builder as any; } type User = { type: 'admin' | 'basic'; name: string; age: number; }; const basicUserBuilder = () => proxyBuilder<User, Omit<User, 'type'>>({ type: 'basic' }); const jane = basicUserBuilder() .type('admin') // 此处希望触发类型错误(隐藏属性) .name('Jane') .age(42) .build(); // 返回类型为Omit<User, 'type'>,不符合预期
问题原因
原代码中,每次调用构建器的属性方法后,返回的类型被断言为SubType,导致构建器的泛型Type被替换成了SubType,最终build()的返回类型被覆盖为SubType而非原始的Type。
解决方案
调整泛型传递逻辑,让构建器始终保留原始目标类型Type,仅用SubType控制可调用的属性:
type ProxyBuilder<Type, SubType = Type> = { // 属性方法返回的构建器仍保留原始Type泛型 [Key in keyof SubType]: (arg: SubType[Key]) => ProxyBuilder<Type, SubType>; } & { build(): Type }; function proxyBuilder<Type, SubType = Type>( defaultValues?: Partial<Type> ): ProxyBuilder<Type, SubType> { const built: Partial<Type> = { ...defaultValues }; const builder = new Proxy( {}, { get: function (_target, prop) { if (prop === 'build') return () => built as Type; return (value: any) => { built[prop as keyof Type] = value; // 返回时断言为保留Type的构建器类型 return builder as ProxyBuilder<Type, SubType>; }; }, } ); return builder as ProxyBuilder<Type, SubType>; } type User = { type: 'admin' | 'basic'; name: string; age: number; }; const basicUserBuilder = () => proxyBuilder<User, Omit<User, 'type'>>({ type: 'basic' }); const jane = basicUserBuilder() // .type('admin') // 此处触发类型错误,符合隐藏属性的需求 .name('Jane') .age(42) .build(); // 现在返回类型为User,符合预期
修改说明
- 泛型传递修正:让
ProxyBuilder的属性方法返回ProxyBuilder<Type, SubType>,确保原始目标类型Type不会被覆盖。 - 类型断言修正:代理中返回构建器时,断言为
ProxyBuilder<Type, SubType>,而非SubType,维持类型链的正确性。 - 类型安全优化:将
built的类型从any改为Partial<Type>,提升类型安全性。
内容的提问来源于stack exchange,提问作者Brian
相关产品推荐
相关产品推荐

