3

This compiles just fine:

class Foo<F> {
  bar: Array<F> = [];

  static create<F, T extends Foo<F>>(this: new () => T): T {
    return new this();
  }
}

class Foo2 extends Foo<string> {}

const foo = Foo2.create();

But if I convert Array<F> to Array<(a: F) => void>, the same code fails:

class Foo<F> {
  bar: Array<(a: F) => void> = [];

  static create<F, T extends Foo<F>>(this: new () => T): T {
    return new this();
  }
}

class Foo2 extends Foo<string> {}

const foo = Foo2.create();
      ^^^
The 'this' context of type 'typeof Foo2' is not assignable to method's 'this' of type 'new () => Foo<unknown>'.
  Types of construct signatures are incompatible.
    Type 'new () => Foo2' is not assignable to type 'new () => Foo<unknown>'.
      Type 'Foo2' is not assignable to type 'Foo<unknown>'.
        Type 'unknown' is not assignable to type 'string'. ts(2684)

It works if I type it manually:

const foo = Foo2.create<string, Foo2>();

So for some reason TypeScript can't infer the string type if it's used in a function argument. Why is this?

3
  • this is a reserved word, this could make issue Commented Sep 19, 2022 at 8:13
  • In static methods it's reserved for this very purpose I believe @BoussadjraBrahim Commented Sep 19, 2022 at 8:15
  • @MarkusMeskanen it looks like what you want already exists in TypeScript as ThisType. Commented Sep 19, 2022 at 8:33

1 Answer 1

1

I'm not sure why TypeScript is not figuring the type out, but I think you had a few mistakes that you got away with anyway, particularly the F type in the method declaration overriding the F in the class itself.

Your code can be simplified as follows:

class Foo<F> {
  bar: Array<(a: F) => void> = [];

  static create<T>(this: new () => T) {
    return new this();
  }
}

class Foo2 extends Foo<string> {}


const foo = Foo2.create();

And it'll work fine:

Playground Link

Update: Sorry, I misread the question originally. The answer has since been updated.

Sign up to request clarification or add additional context in comments.

8 Comments

You seem to have tried the first code that works for me as well, my question is about why the second one doesn't work
Sorry about that, @MarkusMeskanen. Please see the updated answer.
Thank you very much, it seems to work wonderfully! I had never heard of ThisType before, glad to see it exists :)
This is not using ThisType. This is just a generic parameter named ThisType...
I checked the solution for this and found a lot of solutions that work, but none of them support when the parent is generic. Even the creative ones like stackoverflow.com/a/52519934/146656. The thing is that in TypeScript you cannot access generic arguments from static methods.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.