TypeScript 5方法装饰器参数类型校验失效问题修复问询
问题描述
我有一个用于强制校验方法首个参数类型的方法装饰器,在TypeScript 4.9中可正常工作:当方法参数类型不符合指定类型时会触发报错。但升级至TypeScript 5.3(仍启用experimentalDecorators,未使用新标准装饰器)后,错误参数类型不再触发预期报错。
相关代码示例:
interface Foo { foo: string } interface PayloadMap { 'foo': Foo } type TypedMethodDecorator<T> = { (target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<(payload: T) => void>): void; }; declare function MyDecorator<Topic extends keyof PayloadMap, Payload = PayloadMap[Topic]>(topic: Topic): TypedMethodDecorator<Payload>; class TestClass { @MyDecorator('foo') works(payload: Foo) {} // @ts-expect-error: wrong payload type @MyDecorator('foo') nope(payload: string) {} }
TS 4.9环境下的预期错误信息:
Argument of type 'TypedPropertyDescriptor<(payload: string) => void>' is not assignable to parameter of type 'TypedPropertyDescriptor<(payload: Foo) => void>'. Types of property 'value' are incompatible. Type '((payload: string) => void) | undefined' is not assignable to type '((payload: Foo) => void) | undefined'. Type '(payload: string) => void' is not assignable to type '(payload: Foo) => void'.
修复方案
TypeScript 5.3对实验性装饰器的类型推断逻辑做了调整,原定义方式无法有效约束参数类型。需修改装饰器类型,直接对方法参数做逆变校验:
调整后的代码:
interface Foo { foo: string } interface PayloadMap { 'foo': Foo } // 改为泛型类型,直接约束方法的参数数组 type TypedMethodDecorator<T> = <Args extends [T], R>( target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<(...args: Args) => R> ) => void; declare function MyDecorator<Topic extends keyof PayloadMap>(topic: Topic): TypedMethodDecorator<PayloadMap[Topic]>; class TestClass { @MyDecorator('foo') works(payload: Foo) {} // @ts-expect-error: wrong payload type @MyDecorator('foo') nope(payload: string) {} }
关键改动
TypedMethodDecorator<T>改为泛型函数,通过Args extends [T]强制首个参数为T类型- 移除原装饰器的默认泛型参数,直接引用
PayloadMap[Topic],避免类型推断模糊 - 保留返回值泛型
R,不限制方法返回值类型
调整后,TypeScript 5.3会正确校验方法首个参数类型,不符合时触发预期错误。
内容的提问来源于stack exchange,提问作者Trevor Dixon
相关产品推荐
相关产品推荐

