Closed
Description
Motivating example (one of many):
function compare<T>(lhs: T, rhs: T): boolean {
return lhs === rhs;
}
if(compare('1', 1)) { // Expected: Error -- I made 'compare' generic for a reason!
/* ... */
}
Proposal
When generic type inference performs its Best Common Type operation (4.12.2), it should be an error if this returns {}
when {}
was not one of the input types.
This is entirely consistent with other behavior already in the compiler:
var foo = bar ? '1' : 1; // Error, no BCT between '1' and 1
function fn() { // Error, no BCT between '1' and 1
if(foo) {
return '1';
} else {
return 1;
}
}
Open Questions
From @KamyarNazeri -- should this apply when there are zero input types? e.g.:
class List<T> {
items: T[];
}
var x = new List(); // Probably want an error here
That seems desirable, but has some collateral damage:
function foo<T>(x: number, a?: T, b?: T) { }
foo(0); // Error, zero input types provided for inference
This would come up slightly more often than naively expected because many .d.ts authors (mistakenly) create generic types which don't actually consume their type parameters. Perhaps this warning would effectively discourage them from doing so?
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
basarat commentedon Aug 5, 2014
👍
johnnyreilly commentedon Aug 5, 2014
Yes yes yes!
saschanaz commentedon Aug 5, 2014
Great :D
knazeri commentedon Aug 5, 2014
This is really great!
I hope this also includes creating instances from a generic class without the type parameters in the constructor.
@RyanCavanaugh should this apply when there are zero input types?
I think it should, given the example above, type inference fails to correctly address generic instance methods:
DanielRosenwasser commentedon Aug 6, 2014
So @JsonFreeman, @vladima, and I discussed this offline a bit yesterday.
One outstanding question is whether or not we want to error in the case that there are no available candidates to determine the best common type for a type parameter. A good example of this was seen in @KamyarNazeri's example:
Here, our
new
call expression lacks any arguments for which to inferT
.If we do want to error on such a case, then we feel it is worth asking whether we also want to error if a type variable is entirely unused within a type signature.
For instance:
In this example, there will never be candidates for which to instantiate
T1
orT2
's types. Using the simple approach, we would always complain at the call-site.However, we could complain at the definition site instead.
Our feeling is that a type variable that is unused in the signature buys nothing in terms of type safety and utility. There is very little someone can do with a type parameter appearing within a function body if it does not appear within the signature.
JsonFreeman commentedon Aug 6, 2014
I agree with Daniel's comment, although I want to clarify that we don't error on signatures that don't use their own type parameters. So this would be a new error.
Another thing: I don't believe we should error in the absence of inference candidates if the type parameter has a constraint. Instead, we should fall back to the constraint, just like we do for inference results that are not assignable to the constraint.
RyanCavanaugh commentedon Aug 6, 2014
I'm thinking unconsumed generic type parameters in general to be an error under this rule. They're land mines for type inference -- people think that they can just write
interface List<T> { }
and have that work (see the current underscore.d.ts file for good examples), then log bugs when type inference doesn't work because there are no members to infer from.Pre-documenting:
How do I fix "Type argument 'T' is not used in function 'f'" ?
Example:
This is a TypeScript anti-pattern because it implies that
getThing
is the function providing the type safety, when in reality it's the caller who's in control of the type. The better way to write this code is:The only difference here is that
<Animal>
moved to the left ofgetThing
rather than the right. One important note is that we've madegetThing
return{}
instead ofany
. This avoids "implicit"any
types caused by failing to convert the return value:mhegazy commentedon Aug 6, 2014
@RyanCavanaugh I would group this with "Stricter" TypeScript #274, and not with #360
basarat commentedon Aug 7, 2014
👍
👍
8 remaining items
danquirk commentedon Oct 27, 2014
Status on this issue is that per #868 we do now give an error in the original case (multiple candidates leading to {}). The current implementation does not error on the additional suggests in this thread, namely generic inference with 0 candidates and unconsumed generic parameters.
JsonFreeman commentedon Oct 27, 2014
Pull request #951 makes the error for type argument inference failure more informative.
RyanCavanaugh commentedon Dec 2, 2015
We have since fixed this