-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Generic parameter type bounds inference #18611
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
I received a comment via email that doesn't appear to have shown up here. Maybe it was deleted? Anyway, the comment essentially said that I should write |
I agree this is a pain but usually type-inference makes it a non-issue since you don't need to restate any of the types. In this particular example, where a type would need to be stated, you can write let f = <T extends Foo>(x: T) => { }
let g: typeof f = x => f(x); |
This particular example is minimal to illustrate the problem. The |
This is in the vein as #15114. Use-site inference is something we have considered in the past and decided not to pursue. I think in general we can provide better tooling experience both in terms of errors and completions by avoiding non-local/use-site inference. |
I see the parallels, but I don't think this is a duplicate. Type parameters are different than function parameters and deserve separate consideration. It may very well be the case that the same tradeoffs apply, but it's not immediately clear to me that they do. |
It is the same sort of analysis. you would expect it to flow inferences from use sites. so if your let g = <T>(x: T) => f(x) || h(x); then the bounds should be that of if function In general such non-local inferences are possible, and other type systems have implemented them, but there are always trade-offs. we have chosen to build the TS type system on a different design vector. |
Sorry, my example is bad. I'm not actually interested in inference from the body of the function, just within the signature itself. I made my example too minimal and, you're right, I turned it in to a case of the other issue. Please allow me to attempt to re-articulate. Here's another example: interface Value {
tag: string;
}
interface List<T extends Value> extends Value {
tag: 'list',
elements: T[];
}
let count = <T extends Value>(xs: List<T>) => xs.elements.length; I wish I could write: let count = <T>(xs: List<T>) => xs.elements.length; That would be the same kind of use-site analysis, but it's entirely contained by the type signature. I may be mistaken, but I don't think the concerns about complexity and non-locality of error messages apply in quite the same way. |
So you wish an unconstrained generic had an inferred constraint of the intersection of the types of all the constraints the generic must fulfill based on its usages? That is use-site inference; just on type parameters rather than value-level parameters. |
I'd like use-site inference everywhere, but it has been ruled out-of-scope due to complexity at the value level. I get that. What I'm suggesting is that the tradeoffs may be different at the type level. |
That is not accurate. as I noted earlier it is a design choice that we have made early on when we started building TS. We believe explicit types allows us to have better tools, and in turn help us increase JS developer productivity. This applies to both parameters and type parameter upper bounds. |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
Maybe, someone is interested in a RFC in Rust that is accepted and is being implemented. The RFC 2089 Implied bounds is similar to this issue. I think this it is a good idea. |
TypeScript Version: 2.5.1
Overview
There are some similar issues, but I couldn't find one that explicitly addresses this. Apologies if I missed it.
Frequently, I discover that adding type bounds (namely:
extends
) produces cascading boilerplate to all downstream generic code. It's one thing to be forced to propagate type parameters, but it's another entirely to have to propagate type bounds as well.Code
Expected behavior:
The inferred type of
g
should be<T extends Foo>(x: T) => void
.Actual behavior:
An error occurs at the the
x
argument being passed tof
:Related
A similar/related problem occurs with defaults. If
f
had type parameterT extends Foo = Foo
, thenhof
should infer the same default.The text was updated successfully, but these errors were encountered: