能否将对象自身作为其泛型类型?TypeScript技术疑问
如何让对象类型依赖自身作为泛型参数?
问题分析
你当前的核心问题是:给对象标注Queries类型时必须传入泛型参数,但对象尚未定义,无法用typeof obj作为参数传入,导致无法实现函数参数间的依赖约束。同时你定义的Queries和Q类型与实际对象结构(fn1/fn2/fn3)不匹配,需要先对齐结构。
解决方案:用泛型函数实现自动推导与约束
TypeScript不允许直接在对象类型标注中引用自身(对象未定义时typeof obj不存在),但可以通过泛型函数延迟类型推导,让TypeScript在传入对象时自动验证其结构是否符合参数依赖要求。
步骤1:定义约束类型
先明确函数间的依赖关系,定义通用约束类型:
// 基础查询对象结构 type BaseQueryObj = { fn1: () => unknown; fn2: (arg: unknown) => unknown; fn3: (arg: unknown) => null; }; // 约束类型:fn2参数匹配fn1返回值,fn3参数匹配fn2返回值 type ConstrainedQuery<T extends BaseQueryObj> = { fn1: T['fn1']; fn2: (arg: ReturnType<T['fn1']>) => ReturnType<T['fn2']>; fn3: (arg: ReturnType<T['fn2']>) => null; };
步骤2:用泛型函数创建对象
通过泛型函数让TypeScript自动推导并验证约束:
function createConstrainedQuery<T extends ConstrainedQuery<T>>(obj: T): T { return obj; } // 符合约束的正确示例 const validObj = createConstrainedQuery({ fn1: () => 123, // 返回number fn2: (arg: number) => 'test', // 参数匹配fn1返回值,返回string fn3: (arg: string) => null // 参数匹配fn2返回值 }); // 参数不匹配的错误示例(会触发TypeScript报错) const invalidObj = createConstrainedQuery({ fn1: () => 123, fn2: (arg: string) => 'test', // 报错:参数类型与fn1返回值不兼容 fn3: (arg: string) => null });
替代方案:固定结构的递归泛型(可读性较差)
如果不想用函数,也可以用递归泛型直接定义固定结构的类型,但复用性低:
type SelfConstrainedQuery = { fn1: () => number; fn2: (arg: ReturnType<SelfConstrainedQuery['fn1']>) => string; fn3: (arg: ReturnType<SelfConstrainedQuery['fn2']>) => null; }; const obj: SelfConstrainedQuery = { fn1: () => 123, fn2: (arg) => arg.toString(), fn3: (arg) => null };
对原有类型的调整建议
你原来的Queries和Q类型与实际对象结构不匹配,若要保留类似设计,可修改为通用单查询项类型:
// 单查询项的依赖约束类型 type SingleQuery<FnRet, DecoderArg extends FnRet, DecoderRet, TransformArg extends DecoderRet> = { fn: () => FnRet; decoder: (arg: DecoderArg) => DecoderRet; transformationFn: (arg: TransformArg) => any; }; // 多查询项的对象类型 type MultiQueries = { [key: string]: SingleQuery<any, any, any, any>; };
同样,使用泛型函数创建这类对象会更灵活。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

