27

Given a generic class Foo<T> with a static factory method:

class Foo<T>
{
    public static factory(item: T): Foo<T>
    {
        return null;
    }
}

Why does this not compile?

var f = Foo<number>.factory(1);

The error message:

error TS2069: A parameter list must follow a generic type argument list. '(' expected.

This does compile however:

var f = Foo<number>().factory(1);

Why are the parenthesis required? Is this invoking the constructor?

2
  • 1
    It seems odd to not mention the fact that you get a compile error in the top block of code (it is illegal to use type parameters from the containing class in static methods) Commented Jun 18, 2014 at 17:26
  • @RyanCavanaugh, actually I was in the middle of a large refactor and the error message was reported by WebStorm. Their support for TypeScript is ok, but not so comprehensive. Must've missed the error you were talking about, or the error I give masked the one you describe. Commented Jun 18, 2014 at 22:37

3 Answers 3

45

Just as static methods cannot access instance members, the static method cannot use the instance type argument.

For this reason, your static method must be generic and accept a type argument. I highlight this by using U in the static function, and T in the class. It is important to remember that the instance type of T is not the same as the static method type of U.

class Foo<T>
{
    public static factory<U>(item: U): Foo<U>
    {
        return new Foo<U>();
    }

    instanceMethod(input: T) : T
    {
        return input;
    }
}

You then call it by passing the type argument just before the parenthesis, like this:

var f: Foo<number> = Foo.factory<number>(1);

When type inference is possible, the type annotation may be dropped:

var f: Foo<number> = Foo.factory(1);

The variable f is an instance of Foo with a type argument of number, so the instanceMethod method will only accept a value of type number (or any).

f.instanceMethod(123);   // OK
f.instanceMethod('123'); // Compile error
Sign up to request clarification or add additional context in comments.

Comments

1

The point here is, that static generic template is not related to class (and therefore instance) template. So we just have to distinguish them (as in C# I'd say)

// generic here is T
class Foo<T>
{
    public TheT: T;
    constructor(t: T)
    {
        this.TheT = t;
    }

    // the static one is U
    public static factory<U>(item: U): Foo<U>
    {
        var result = new Foo<U>(item);
        // the U here will be T inside of the instance
        return result;
    }
}

and we can call it like:

var f = Foo.factory(<Number> 1);

Comments

0

I think what is happening is that the TypeScript compiler is seeing Foo<number> and is expecting this to be an object type i.e.

var f: Foo<number>;

Since the class is compiled to a scoped function in javascript, when adding the parenthesis you are effectively initialising the object yes.

Typescript probably raises a compile error without the () because it can't assume that you meant to initialise the class.

Comments

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.