TypeScript中T与void联合类型引发装饰器类型不兼容问题求助
TypeScript装饰器类型兼容问题的替代解决方案
问题根源在于当前Test装饰器返回的方法类型(...args: any[]) => InstanceType<T> | void包含了void,但test2方法声明必须返回Message,导致类型不兼容。以下是几种无需修改test2返回类型的解决办法:
方案一:给装饰器添加函数重载
通过重载明确区分传参和不传参两种场景的返回类型,让TypeScript自动匹配对应类型:
class Message { value: string; } type Class = { new (...args: any[]): any }; // 重载1:不传type时,返回允许void的方法类型 function Test(): ( target: object, key: string | symbol, descriptor: PropertyDescriptor ) => TypedPropertyDescriptor<(...args: any[]) => void> | void; // 重载2:传type时,返回仅包含目标实例类型的方法类型 function Test<T extends Class>(type: T): ( target: object, key: string | symbol, descriptor: PropertyDescriptor ) => TypedPropertyDescriptor<(...args: any[]) => InstanceType<T>> | void; // 装饰器实现 function Test<T extends Class>(type?: T) { return ( target: object, key: string | symbol, descriptor: PropertyDescriptor ): TypedPropertyDescriptor< (...args: any[]) => InstanceType<T> | void > | void => { }; } class Controller { @Test() test(): void { } @Test(Message) test2(): Message { return { value: 'test2' } } }
方案二:使用条件泛型动态推断返回类型
通过泛型条件判断,根据是否传入type参数自动生成对应的返回类型,无需手动写重载:
class Message { value: string; } type Class = { new (...args: any[]): any }; // 第二个泛型参数R根据T是否存在动态推断返回类型 function Test<T extends Class | undefined = undefined, R = T extends Class ? InstanceType<T> : void>(type?: T) { return ( target: object, key: string | symbol, descriptor: PropertyDescriptor ): TypedPropertyDescriptor<(...args: any[]) => R> | void => { }; } class Controller { @Test() test(): void { } @Test(Message) test2(): Message { return { value: 'test2' } } }
方案三:适配原方法参数并精确控制返回类型
让装饰器兼容原方法的参数类型,同时根据type参数精确控制返回类型,提升类型严谨性:
class Message { value: string; } type Class = { new (...args: any[]): any }; // 用泛型M表示原方法的类型,保证参数匹配 function Test<T extends Class | undefined = undefined>(type?: T) { return <M extends (...args: any[]) => any>( target: object, key: string | symbol, descriptor: TypedPropertyDescriptor<M> ): TypedPropertyDescriptor< // 有type则返回目标实例类型,否则保留原方法返回类型 T extends Class ? (...args: Parameters<M>) => InstanceType<T> : M > | void => { }; } class Controller { @Test() test(): void { } @Test(Message) test2(): Message { return { value: 'test2' } } }
内容的提问来源于stack exchange,提问作者George Hulpoi
相关产品推荐
相关产品推荐

