TypeScript中如何推断泛型参数的泛型类型参数?
TypeScript操作装饰器的类型推断问题解决
问题背景
首先定义了表示操作的泛型类型:
type Operation<A, B> = { execute: (data: A) => B; };
操作示例:
const op = { execute: (data: string) => { return data; }, };
为给操作添加事务处理功能,同时保留原操作的所有字段,实现了装饰器函数:
export const wrapInTransaction = <A, B, O extends Operation<A, B>>( { execute, ...rest}: O ): O => { const wrappedExecute = (data: A) => { // 添加事务逻辑 return execute(data) } return { ...rest, execute: wrappedExecute, } as O; }
调用时出现类型错误:
const wrapped = wrapInTransaction(op); // Argument of type '{ execute: (data: string) => string; }' is not assignable to parameter of type 'Operation<unknown, unknown>'. // Types of property 'execute' are incompatible. // Type '(data: string) => string' is not assignable to type '(data: unknown) => unknown'. // Types of parameters 'data' and 'data' are incompatible. // Type 'unknown' is not assignable to type 'string'
问题原因
TypeScript的泛型推断顺序导致了这个问题:当泛型参数顺序是<A, B, O extends Operation<A, B>>时,TypeScript会先尝试推断A和B,但此时没有足够上下文,会将A、B推断为unknown,进而导致O的约束变成Operation<unknown, unknown>,与传入的op类型不匹配。
解决方案
调整泛型参数的推断逻辑,让TypeScript先推断O的具体类型,再从O中提取A和B的类型,有两种常用方式:
方式1:使用条件类型自动提取A和B
export const wrapInTransaction = <O extends Operation<any, any>>( { execute, ...rest }: O ): O => { // 从O的execute方法中提取参数和返回值类型 type A = Parameters<O['execute']>[0]; type B = ReturnType<O['execute']>; const wrappedExecute = (data: A): B => { // 这里添加事务处理逻辑 console.log("开始事务"); const result = execute(data); console.log("结束事务"); return result; }; return { ...rest, execute: wrappedExecute, } as O; };
方式2:调整泛型参数顺序并使用infer
export const wrapInTransaction = <O extends Operation<infer A, infer B>>( { execute, ...rest }: O ): O => { const wrappedExecute = (data: A): B => { // 添加事务逻辑 return execute(data); }; return { ...rest, execute: wrappedExecute, } as O; };
两种方式都能让TypeScript正确推断出op的类型,进而正确匹配A为string、B为string,避免类型不兼容的错误。
内容的提问来源于stack exchange,提问作者Adam A
相关产品推荐
相关产品推荐

