在Typescript中如何获取在工厂(ish)函数中实例化的类上的方法的通用返回类型

sno*_*dev 5 generics types typescript

在下面的示例代码中,TypeScript 无法推断函数中的泛型类型UfooBar因此返回类型fooRef.doIt()unknown。为什么会这样,我需要修改什么才能获得正确的返回类型?

interface Foo<T> {
  foo(): T;
}

class Bar implements Foo<string> {
  foo(): string {
    return 'Bar';
  }
}

class Baz implements Foo<number> {
  foo(): number {
    return 43;
  }
}

class FooRef<T extends Foo<U>, U> {
  constructor(private instance: T) {}

  doIt() {
    return this.instance.foo();
  }
}

function fooBar<T extends Foo<U>, U>(foo: new (...args: any[]) => T) {
  return new FooRef(new foo());
}

const barRef = fooBar(Bar);
barRef.doIt(); // unknown, expected string

const bazRef = fooBar(Baz);
bazRef.doIt(); // unknown, expected number
Run Code Online (Sandbox Code Playgroud)

sno*_*dev 0

这个答案的灵感来自@jcalz 在评论中的建议。我无法按照infer他的建议使用 使其工作,但他的建议使用ReturnType按预期工作,这就是我在这里使用的。

interface Foo<T> {
    foo(): T;
}

class Bar implements Foo<string> {
    foo(): string {
        return 'Bar';
    }
}

class Baz implements Foo<number> {
    foo(): number {
        return 43;
    }
}

class FooRef<T extends Foo<U>, U = ReturnType<T["foo"]>> {
    constructor(public instance: T) { }

    doIt(): U {
        return this.instance.foo();
    }
}

function fooBar<T extends Foo<any>>(foo: new (...args: any[]) => T) {
    return new FooRef(new foo());
}

const barRef = fooBar(Bar);
barRef.instance // (property) FooRef<Bar, string>.instance: Bar
console.log(barRef.doIt().toUpperCase()); // "BAR"

const bazRef = fooBar(Baz);
bazRef.instance // (property) FooRef<Baz, number>.instance: Baz 
console.log(bazRef.doIt().toFixed(2)) // "43.00"
Run Code Online (Sandbox Code Playgroud)