max taldykin
max taldykin

Reputation: 12898

Inconsistent behavior of enum as constrained parameter in generic

Why it is not possible to cast something that extends number to number?

Here is simple example in which I'm trying to pass enum as a generic argument to function.

enum Ev {A, B}

function fun<E extends number>(x: {[ix: number]: any}, e: E)
{
    return x[<number>e]
}

// no error here, so I assume is true that `Ev extends number`
fun({0:0}, Ev.A)

It seems a bit inconsistent that some type extends number but I get this error when trying to cast it to number:

Neither type 'E' nor type 'number' is assignable to the other.

Edit: Here is almost the same example but with class instead of number (this compiles without error):

class A {}

function fun<E extends A>(x: {[ix: number]: any}, e: E)
{
    return x[<A>e]
}

Upvotes: 0

Views: 707

Answers (2)

David Sherret
David Sherret

Reputation: 106660

Why it is not possible to cast something that extends number to number?

As Ryan has pointed out in this issue, it seems like a bug in the language; however, take note that this form of constraint is only useful when the return type of the function is the constraint on the type parameter. For example:

function f<T extends number>(input: T) : T { return input; }
var t = f(Ev.A); // t : Ev

An issue with the constraint in the function you provided, is that it doesn't prevent passing in a number value. Since it's not possible to constrain to an enum member, you might as well just define your function with the constraint on the parameter instead:

function fun(x: {[ix: number]: any}, e: number)
{
    return x[e];
}

A complaint you had with doing this was that it wasn't self documenting code. I would say it's better to give your function a descriptive name that says its intent rather than relying on generics that offer no constraint benefit beyond a number constraint. Also remember that there's no way to force a developer to write the generic part when calling the function. They can easily write fun({0:0}, Ev.A) instead of fun<Ev>({0:0}, Ev.A).

Upvotes: 0

James Wilkins
James Wilkins

Reputation: 7367

Primitive types cannot be inherited from, as some have special "abilities" that require a special instance, and creating a new derived object would prevent that ability. For instance, there is no way to call the string constructor for a new custom derived object, so no way to apply it to a user instance. This is why nothing inherits from number, or anything else.

Upvotes: 2

Related Questions