英文:
Return type is not assignable to unknown using TypeScript 5 decorators
问题
尝试实现新的TypeScript 5装饰器,但我面临一个我不理解的类型问题。下面是一个简单的示例,TS PLAYGROUND HERE
错误信息如下:
装饰器函数的返回类型'(this: ProductsService, ...args: any[]) => unknown'无法分配给类型'void | ((mockProducts: any) => Promise<TProductsDtoOutput[]>)'。
类型'(this: ProductsService, ...args: any[]) => unknown'无法分配给类型'(mockProducts: any) => Promise<TProductsDtoOutput[]>'。
类型'unknown'无法分配给类型'Promise<TProductsDtoOutput[]>'。
export function loggedMethod<This, Args extends any[], Return, Fn extends (this: This, ...args: Args) => Return>(
  target: Fn,
  context: ClassMethodDecoratorContext<This, Fn>
) {
  const methodName = String(context.name);
  function replacementMethod(this: This, ...args: Args): Return {
    console.log(`LOG : 进入方法 "${methodName}"`);
    const result = target.call(this, ...args);
    console.log(`LOG : 退出方法 "${methodName}"`);
    return result;
  }
  return replacementMethod;
}
type TProductsDtoOutput = {
  all: string;
}
export class ProductsService {
  @loggedMethod
  async getAll(mockProducts: any): Promise<TProductsDtoOutput[]> {
    const result = mockProducts.map((product: any) => {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { id, ...rest } = product;
      return rest as TProductsDtoOutput;
    });
    return result;
  }
}
英文:
Trying to implement the new TypeScript 5 decorators, but I'm facing a typing issue that I do not understand.
Below is the simple example, TS PLAYGROUND HERE
Error is:
> 
>    Decorator function return type '(this: ProductsService, ...args: any[]) => unknown' is not assignable to type 'void | ((mockProducts: any) => Promise<TProductsDtoOutput[]>)'.
>      Type '(this: ProductsService, ...args: any[]) => unknown' is not assignable to type '(mockProducts: any) => Promise<TProductsDtoOutput[]>'.
>        Type 'unknown' is not assignable to type 'Promise<TProductsDtoOutput[]>'.
> 
export function loggedMethod<This, Args extends any[], Return, Fn extends (this: This, ...args: Args) => Return>(
  target: Fn,
  context: ClassMethodDecoratorContext<This, Fn>
) {
  const methodName = String(context.name);
  function replacementMethod(this: This, ...args: Args): Return {
    console.log(`LOG : Entering Method "${methodName}"`);
    const result = target.call(this, ...args);
    console.log(`LOG : Exiting Method "${methodName}"`);
    return result;
  }
  return replacementMethod;
}
type TProductsDtoOutput = {
    all:string
}
export class ProductsService {
  @loggedMethod
  async getAll(mockProducts:any): Promise<TProductsDtoOutput[]> {
    const result = mockProducts.map((product:any) => {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { id, ...rest } = product;
      return rest as TProductsDtoOutput;
    });
    return result
  }
}
答案1
得分: 1
TS在这种情况下不会自动推断第一个泛型参数。请手动推断,然后这将起作用。
export function loggedMethod<Fn extends (...args: any[]) => any>(
  target: Fn,
  context: ClassMethodDecoratorContext<ThisParameterType<Fn>, Fn>
) {
  const methodName = String(context.name);
  return function replacementMethod(this: ThisParameterType<Fn>, ...args: Parameters<Fn>) {
    console.log(`LOG : 进入方法 "${methodName}"`);
    const result = target.call(this, ...args);
    console.log(`LOG : 离开方法 "${methodName}"`);
    return result;
  }
}
英文:
TS does not infer first generics in this case. Infer them manually then this will work.
export function loggedMethod<Fn extends (...args: any[]) => any>(
  target: Fn,
  context: ClassMethodDecoratorContext<ThisParameterType<Fn>, Fn>
) {
  const methodName = String(context.name);
  return function replacementMethod(this: ThisParameterType<Fn>, ...args: Parameters<Fn>) {
    console.log(`LOG : Entering Method "${methodName}"`);
    const result = target.call(this, ...args);
    console.log(`LOG : Exiting Method "${methodName}"`);
    return result;
  }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论