输入重载的 class 方法

Typing an overloaded class method

我需要围绕按参数类型重载的方法 foo 编写一个包装器。

更新:A 扩展 B

更新 2:TS playground link

const getFoo: {
   foo(x: number, y?: A): A;
   foo(x: number, y?: B): B;
}

在我启用了 TS IntelliSense 的 IDE 中,const a = foo(1, {} as A)A 类型,const b = foo(1, {} as B})B 类型。所以,重载正在工作。

我的包装函数:

const fooWrapper = () => {
  const { foo } = getFoo();
  return {
     modifiedFoo: <T extends A | B>(x: number, y?: T) => {
        // my code
        return foo(x, y);
     }
  }

但是,const c = modifiedFoo(1, {} as A)B 类型,而不是您期望的 A

正在尝试将 return 类型添加到 modifiedFoo:

modifiedFoo: <T extends A | B>(x: number, y?: T):
  T extends A
  ? A
  : T extends B
  ? B
  : never

修复了 modifiedFoo 的 return 类型,但它在 return foo(x, y) 行的 modifiedFoo 定义中导致编译器问题,声明

Type 'B' is not assignable to type 'T extends A ? A : T extends B ? B : never'
Type 'A' is not assignable to type 'T extends A ? A : T extends B ? B : never'

对我来说很奇怪,我可以调用 return foo(x, y as A)modifiedFoo 总是 return A,或者 return foo(x, y as B) 得到 modifiedFoo 总是 return B,但是泛型 returnFoo(x, y) y 是类型 T 不是 return 正确的类型,除非我添加明确的 return 导致编译器错误的类型定义。

回答并说明:

type OverloadedParams<T> = T extends { (...o: infer U1): any; (...o: infer U2): any } ? U1 | U2 : never;

type OverloadedReturn<T, U> = Extract<
 T extends {
     (...args: infer A1): infer R1;
     (...args: infer A2): infer R2;
 } ? U extends A1 ? [U, R1] : U extends A2 ? [U, R2] : never : never, [U, any]
>[1];

const gWrapper = () => {
    const { foo } = getG();
    return <T extends OverloadedParams<G["foo"]>>(...args: T): OverloadedReturn<G["foo"], T> => {
        return foo(args[0], args[1]);
    }
}

Playground link

关键是获取重载参数类型(而非子类型)的父类型,并使用重载函数的定义将其与适当的 return 类型相关联。

我仍然不明白,为什么花了这么长时间才解决,是为什么

type OverloadedReturn<T, U> =  T extends {
     (...args: infer A1): infer R1;
     (...args: infer A2): infer R2;
 } ? U extends A1 ? R1 : U extends A2 ? R2 : never : never;

无效。